洛谷线段树1
开long long是因为int最后三组数据过不了
#include<bits/stdc++.h>
using namespace std;
const int N=100001;
long long x,y,z,n,m,q;
long long d[N*4],a[N],b[4*N];//树的范围一般开4N
//【s,t】为当前区间 ,p为当前根节点序号
void build(long long s,long long t,long long p){//建树
if(s==t){
d[p]=a[s];
return ;
}
long long m=s+((t-s)>>1);//等价于s+t/2,但可防超出int范围;
build(s,m,p*2);
build(m+1,t,p*2+1);
//对左右区间建树
d[p]=d[p*2]+d[(p*2)+1];
}
//【l,r】为修改区间,【s,t】为当前区间,c为更新值,p为当前根节点序号
void update(long long l,long long r,long long c,long long s,long long t,long long p) {//更新
if(l<=s&&t<=r){
d[p]+=(t-s+1)*c,b[p]+=c;
return;
}
long long m=s+((t-s)>>1);
if(b[p]&&s!=t){//懒惰标记下放
d[p*2]+=b[p]*(m-s+1),d[p*2+1]+=b[p]*(t-m);
b[p*2]+=b[p],b[p*2+1]+=b[p];
b[p]=0;
}
if(l<=m)update(l,r,c,s,m,p*2);
if(r>m)update(l,r,c,m+1,t,p*2+1);
d[p]=d[p*2]+d[p*2+1];
}
/*懒惰标记,
简单来说,就是通过延迟对节点信息的更改,
从而减少可能不必要的操作次数。每次执行
修改时,我们通过打标记的方法表明该节点
对应的区间在某一次操作中被更改,但不更
新该节点的子节点的信息。实质性的修改则
在下一次访问带有标记的节点时才进行。*/
long long getsum(long long l,long long r,long long s,long long t,long long p){//查询求和
if(l<=s&&t<=r)//当前区间为询问区间的子集时直接返回当前区间的和
return d[p];
long long m=s+((t-s)>>1);//等价于s+t/2,但可防超出int范围
long long sum=0;
if(b[p]){//有需求的下放懒惰标记
d[p*2]+=b[p]*(m-s+1),d[p*2+1]+=b[p]*(t-m);
b[p*2]+=b[p],b[p*2+1]+=b[p];
b[p]=0;
}
if(l<=m)sum+=getsum(l,r,s,m,p*2);
//如果左儿子代表的区间 [l, m] 与询问区间有交集, 则递归查询左儿子
if(r>m)sum+=getsum(l,r,m+1,t,p*2+1);
//同上
return sum;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,n,1);
for(int i=1;i<=m;i++){
cin>>q;
if(q==1){
cin>>x>>y>>z;
update(x,y,z,1,n,1);
}
if(q==2){
cin>>x>>y;
cout<<getsum(x,y,1,n,1)<<endl;
}
}
return 0;
}