之前由于不会延迟标记一直没写这题。
那么今天就写一个总结来加深印象吧!
首先,延迟标记的作用就是在于当某个区间遭到改变,但又用不上(不用输出)时。将所有先前改变都标记上去,等到要用到了,一次直接改。
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
struct segment_tree{
int l,r;
long long v,add;//加一个延迟标记的变量
}t[maxn*4];
long long a[4*maxn];
void build_up(int x,int l,int r){
int mid=(l+r)/2;
t[x].l=l;t[x].r=r;
if (l==r){t[x].v=a[l];return ;}
build_up(x*2,l,mid);
build_up(x*2+1,mid+1,r);
t[x].v=t[x*2].v+t[x*2+1].v;//标准建树
}
void spread(int x){
if (t[x].add){
t[x*2].v+=t[x].add*(t[x*2].r-t[x*2].l+1);
t[x*2+1].v+=t[x].add*(t[x*2+1].r-t[x*2+1].l+1);//更改区间值
t[x*2].add+=t[x].add;//两个子树加上标记
t[x*2+1].add+=t[x].add;
t[x].add=0;//清空当前标记
}
}
void change(int x,int l,int r,long long d){
int mid=(t[x].l+t[x].r)/2;
if (l<=t[x].l&&r>=t[x].r){//若此节点被整个更改区间覆盖
t[x].v+=d*(t[x].r-t[x].l+1);
t[x].add+=d;//(接上)则可以直接更改它的值,并加上标记
return ;
}
spread(x);//若没有,则直接向下改
if (l<=mid) change(x*2,l,r,d);
if (r>mid) change(x*2+1,l,r,d);
t[x].v=t[x*2].v+t[x*2+1].v;//这时再改值
}
long long ask(int x,int l,int r){
if (l<=t[x].l&&r>=t[x].r)return t[x].v;//如果被当前区间覆盖,就可以直接输出值了
spread(x);//若没有,则向下标记
int mid=(t[x].l+t[x].r)/2;
long long val=0;
if (l<=mid) val+=ask(x*2,l,r);
if (r>mid) val+=ask(x*2+1,l,r);
return val;
}
//void merge(int x,int y){
// spread(t[x].l,t[x].r);
// if (t[x].l!=t[x].r)
//}
int main(){
int i,m,n;
cin>>n>>m;
for (i=1;i<=n;i++)
cin>>a[i];
build_up(1,1,n);
for (i=1;i<=m;i++){
int x,y,z;
long long k;
cin>>x>>y>>z;
if (x==1){
cin>>k;
change(1,y,z,k);
}
else cout<<ask(1,y,z)<<endl;
}
return 0;
}