为了那不可知的询问永远坚守于此
解析
众所周知线段树的区间修改是需要打懒标记的
多数时候,这个标记在询问子区间时需要下传
而标记永久化,就是指不下传懒标记的一种操作
在某些时候标记不便下传时有所应用
比如zkw线段树和二维线段树等
然而zkw线段树我并不会
还能起到一定的常数优化作用 (这是真的卡常卡疯了)
这个操作是有局限性的
那就是:不可逆性
比如说
标记永久化可以维护区间赋值和维护最大值
但前提是区间赋值必须不小于区间内原来的值
否则就无法操作
细节: pushup的时候一定要把自己身上的懒标记考虑在内!!
代码
(线段树1)
//#include<bits/stdc++.h>
#include<cstdio>
#include<cctype>
#include<algorithm>const int N=5e5+100;
const int mod=1e9+7;
#define ll long long
using namespace std;
inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m,k;#define mid ((l+r)>>1)
#define ls (k<<1)
#define rs (k<<1|1)
ll tr[N<<2],laz[N<<2],a[N];
inline void add(int k,int l,int r,ll v){laz[k]+=v;tr[k]+=(r-l+1)*v;return;
}
inline void pushup(int k,int l,int r){tr[k]=tr[ls]+tr[rs]+(r-l+1)*laz[k];
}
void build(int k,int l,int r){if(l==r){tr[k]=a[l];return;}build(ls,l,mid);build(rs,mid+1,r);pushup(k,l,r);return;
}
void change(int k,int l,int r,int x,int y,ll v){if(x<=l&&r<=y){//printf("add:(%d %d)\n",l,r);add(k,l,r,v);return;}if(x<=mid) change(ls,l,mid,x,y,v);if(y>mid) change(rs,mid+1,r,x,y,v);pushup(k,l,r);return;
}
ll ask(int k,int l,int r,int x,int y){if(x<=l&&r<=y) return tr[k];ll res=(min(y,r)-max(x,l)+1)*laz[k];if(x<=mid) res+=ask(ls,l,mid,x,y);if(y>mid) res+=ask(rs,mid+1,r,x,y);//printf("(%d %d) res=%lld\n",l,r,res);return res;
}
int main(){#ifndef ONLINE_JUDGE//freopen("a.in","r",stdin);//freopen("a.out","w",stdout);#endifn=read();m=read();for(int i=1;i<=n;i++) a[i]=read();build(1,1,n);for(int i=1;i<=m;i++){char c;int x,y,z;scanf(" %c%d%d",&c,&x,&y);if(c=='Q') printf("%lld\n",ask(1,1,n,x,y));else{z=read();change(1,1,n,x,y,z);}}return 0;
}
/*
5 3
7 1 4 1 9
1 3 5 3
1 1 4 2
2 3 5
*/