关于线段树的原理
一颗树,一个节点表一个区间,以此来求和。
而根节点表示1 - N,其左节点表1 - mid,右节点 mid +1 - N。
先写一个线段树模板。
#include<bits/stdc++.h>
using namespace std;
const int N = 1000000+10;
struct Node{
long long sum,add;
};
Node sgt[N*4];
int a[N];
void build(int index,int begin,int end){
if(begin == end){
sgt[index].sum = a[begin];
return ;
}
int mid = (begin+end)/2;
build(index*2,begin,mid);
build(index*2+1,mid+1,end);
sgt[index].sum = sgt[index*2].sum+sgt[index*2+1].sum;
}
void push_down(int index,int begin,int end){
sgt[index*2].add += sgt[index].add;
sgt[index*2+1].add += sgt[index].add;
sgt[index].sum += sgt[index].add*(end-begin+1);
sgt[index].add = 0;
}
void update(int index,int begin,int end,int left,int right,int x){
if(begin == left&&right == end){
sgt[index].add += x;
return ;
}
sgt[index].sum += 1LL*x*(right -left + 1);
push_down(index,begin,end);
int mid = (begin+end)/2;
if(right <= mid){
update(index*2,begin,mid,left,right,x);
}
else if(left > mid){
update(index*2+1,mid+1,end,left,right,x);
}
else{
update(index*2,begin,mid,left,mid,x);
update(index*2+1,mid+1,end,mid+1,right,x);
}
}
long long query(int index,int begin,int end,int left,int right){
if(begin == left&&right == end){
return sgt[index].sum+sgt[index].add*(end-begin+1);
}
push_down(index,begin,end);
int mid = (begin+end)/2;
if(right <= mid) return query(index*2,begin,mid,left,right);
else if(left > mid)return query(index*2+1,mid+1,end,left,right);
else{
return query(index*2,begin,mid,left,mid)+query(index*2+1,mid+1,end,mid+1,right);
}
}
int main(){
int n,q;
scanf("%d %d",&n,&q);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
}
build(1,1,n);
while(q--){
int op;
scanf("%d",&op);
if(op == 1){
int i,j,x;
scanf("%d%d%d",&i,&j,&x);
update(1,1,n,i,j,x);
}
else{
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",query(1,1,n,l,r));
}
}
return 0;
}
易错点
sgt[index].sum += 1LL*x*(right -left + 1);
一定不要忘记加上这一行代码,不然就没加上x了!