最近学到线段树,于是就写了个板子.
#include<cstdio>
struct node{
int L,R;
long long add,sum;
void Add(int t){
sum+=t*(R-L+1);
add+=t;
}
};
struct Segmenttree{
node tree[400005];//注意要开四倍的数组
int A[400005];
void Up(int p){
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
}
void Down(int p){
long long&t=tree[p].add;
if(!t)return;
tree[p<<1].Add(t);
tree[p<<1|1].Add(t);
t=0;
}
void Build(int L,int R,int p){
tree[p].L=L,tree[p].R=R;
if(L==R){
tree[p].sum=A[L];
return;
}
int mid=(tree[p].L+tree[p].R)>>1;//二分建树
if(R<=mid)Build(L,R,p<<1);//都在mid的左边
else if(L>mid)Build(L,R,p<<1|1);//都在mid的右边
else Build(L,mid,p<<1),Build(mid+1,R,p<<1|1);//既在mid左边,又在mid右边
Up(p);//从子树收集状态
}
void Add(int L,int R,int d,int p){
if(tree[p].L==L&&tree[p].R==R){//两个边界相同则直接返回
tree[p].sum+=(R-L+1)*d;
tree[p].add+=d;
return;
}
Down(p);//将附加值向下传递
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)Add(L,R,d,p<<1);
else if(L>mid)Add(L,R,d,p<<1|1);
else {
Add(L,mid,d,p<<1);
Add(mid+1,R,d,p<<1|1);
}
Up(p);
}
long long Query(int L,int R,int p){
if(tree[p].L==L&&tree[p].R==R){
return tree[p].sum;
}
Down(p);
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)return Query(L,R,p<<1);
else if(L>mid)return Query(L,R,p<<1|1);
else return Query(L,mid,p<<1)+Query(mid+1,R,p<<1|1);
}
}S;
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&S.A[i]);
S.Build(1,n,1);//建树函数
while(m--){
int a,x,y,k;
scanf("%d",&a);
if(a==1){
scanf("%d%d%d",&x,&y,&k);
S.Add(x,y,k,1);
}else {
scanf("%d%d",&x,&y);
printf("%lld\n",S.Query(x,y,1));
}
}
}