#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
ll lazytag[400010],sumv[400010],a[400010];
inline void pushup(const int &o){
sumv[o]=sumv[o<<1]+sumv[o<<1|1];
}
inline void build(const int &o,const int&l,const int&r){
if(l==r){
sumv[o]=a[l];
return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);
}
inline void change2(const int&o,const int&l,const int &r,const int &ql,const int&qr,const ll&k){
if(l==ql&&r==qr){
sumv[o]+=k*(qr-ql+1);
lazytag[o]+=k;
return ;
}
if(qr<ql)return ;
if(ql<l||qr>r)return ;
int mid=(l+r)>>1;
if(ql<=mid&&qr<=mid){
change2(o<<1,l,mid,ql,qr,k);
sumv[o]+=(qr-ql+1)*k;
return ;
}
if(qr>mid&&ql>mid){
change2(o<<1|1,mid+1,r,ql,qr,k);
// pushup(o);
sumv[o]+=k*(qr-ql+1);
return ;
}
if(ql<=mid&&qr>mid){
change2(o<<1,l,mid,ql,mid,k);
change2(o<<1|1,mid+1,r,mid+1,qr,k);
// pushup(o);
sumv[o]+=(qr-ql+1)*k;
return ;
}
}
inline ll querys(const int&o,const int&l,const int&r,const int&ql,const int&qr){
if(l==ql&&r==qr){
return sumv[o];
}
if(qr<ql)return 0;
if(ql<l||qr>r)return 0;
int mid=(l+r)>>1;
if(ql<=mid&&qr<=mid){
return querys(o<<1,l,mid,ql,qr)+lazytag[o]*(qr-ql+1);
}
if(ql>mid&&qr>mid){
return querys(o<<1|1,mid+1,r,ql,qr)+lazytag[o]*(qr-ql+1);
}
if(ql<=mid&&qr>mid){
return querys(o<<1,l,mid,ql,mid)+querys(o<<1|1,mid+1,r,mid+1,qr)+lazytag[o]*(qr-ql+1);
}
}
int main(){
memset(lazytag,0,sizeof lazytag);
memset(sumv,0,sizeof sumv);
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i)cin>>a[i];
build(1,1,n);
for(int i=1;i<=m;++i){
int opt;
cin>>opt;
if(opt==1){
int x,y;ll k;
cin>>x>>y>>k;
change2(1,1,n,x,y,k);
}else{
int x,y;
cin>>x>>y;
cout<<querys(1,1,n,x,y)<<endl;
}
}
return 0;
}
已经a了这道题,但是我这个线段树在区间修改时没有下传标记,而是把上面的部分处理了,并打标记,然后查询时如果查到有标记就直接加上k*(待查询区间长度)