线段树(英语:Segment tree)是一种二叉树形数据结构,1977年由Jon Louis Bentley发明[1],用以储存区间或线段,并且允许快速查询结构内包含某一点的所有区间。 一个包含n个区间的线段树,空间复杂度为O(nlogn),查询的时间复杂度则为O(log n+k),其中k是符合条件的区间数量。
——摘自维基百科
显然,当我们需要进行区间查询时,n^2算法无疑是最容易想到的,但也是效率最低的,所以用线段树可以用更短的时间来进行查询和修改。
具体思路分析见本题题解
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[100005]; //存储原始数组
class Segment_Tree{
public:
ll node[100005]; //存放节点编号
ll tag[100005]; //存放懒惰标记
public:
// Segment_Tree(){
// node = new ll[400005];
// tag = new ll[400005];
// }
//
// Segment_Tree(int size){
// node = new ll [2*size+1];
// tag = new ll[2*size+1];
// }
inline ll left_child(ll p){
return 2*p;
}
inline ll right_child(ll p){
return 2*p+1;
}
void push_up(ll p){ //向上维护区间和
node[p] = node[left_child(p)] + node[right_child(p)];
}
void build(ll l, ll r, ll p){
tag[p] = 0;
if(l == r){
node[p] = a[l];
return;
}
ll mid = (l+r)/2;
build(l,mid,left_child(p));
build(mid+1,r,right_child(p));
push_up(p);
}
void edit(ll l, ll r, ll p, ll k){ //修改p
tag[p] += k;
node[p] += (r-l+1)*k;
}
void push_down(ll l, ll r, ll p){ //向下维护懒惰标记
ll mid = (l+r)/2;
edit(l,mid,left_child(p),tag[p]);
edit(mid+1,r,right_child(p),tag[p]);
tag[p] = 0; //归零
}
void update(ll nl, ll nr, ll l, ll r, ll p, ll k){
//nl,nr为需要修改的区间
if(nl <= l && r <= nr){ //[l,r]包含在[nl,nr]内,则直接修改即可
node[p] += (r-l+1)*k;
tag[p] += k;
return;
}
push_down(l,r,p);
ll mid = (l+r)/2;
if(nl <= mid)
update(nl, nr, l, mid, left_child(p), k);
if(nr >= mid+1)
update(nl, nr, mid+1, r, right_child(p), k);
push_up(p);
}
ll search(ll nl, ll nr, ll l, ll r, ll p){
//nl,nr为需要查询的区间
if(nl <= l && nr >= r){
return node[p];
}
ll mid = (l+r)/2;
push_down(l,r,p);
ll x = 0;
if(nl <= mid)
x += search(nl,nr,l,mid,left_child(p));
if(nr >= mid+1)
x += search(nl,nr,mid+1,r,right_child(p));
return x;
}
};
int main()
{
int m,n;
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
scanf("%lld",&a[i]);
}
Segment_Tree st;
st.build(1,n,1);
int x;
ll a,b,c,d,e;
for (int i = 0; i < m; ++i) {
scanf("%d",&x);
if(x == 1){
scanf("%lld %lld %lld", &a, &b, &c);
st.update(a,b,1,n,1,c);
}
else{
scanf("%lld %lld", &d, &e);
ll x = st.search(d,e,1,n,1);
printf("%lld\n",x);
}
}
return 0;
}