题意:
思路:
每次修改,就新开一个树,如果大小是l到r包含叶子节点的一颗树自然是不可以的,那么我们只能保存包含他们的上面的节点,并且lazy也要同步更新(这一步和线段树很类似),但是,我们并不能pushdown,因为pushdown会直接导致空间炸掉。
那么我们为了能够用到lazy,那么我们就可以将路径上的lazy加起来,最后和区间大小相乘,就是正确的最终结果
错误及反思:
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m
#define rson m+1,r
const int N = 100100;
long long sum[N*30];
int ls[N*30],rs[N*30],root[N],arr[N],lazy[N*30];
int n,q,cnt,t;
int build(int l,int r){
int rt=++cnt;
sum[rt]=arr[l];ls[rt]=rt;rs[rt]=rt;lazy[rt]=0;
if(l==r) return rt;
int m=l+r>>1;
ls[rt]=build(lson); rs[rt]=build(rson);
sum[rt]=sum[ls[rt]]+sum[rs[rt]];
return rt;
}
int update(int pre,int L,int R,int val,int l,int r){
int rt=++cnt;
sum[rt]=sum[pre];ls[rt]=ls[pre];rs[rt]=rs[pre];lazy[rt]=lazy[pre];
if(L<=l&&R>=r) {lazy[rt]+=val;sum[rt]+=1ll*(r-l+1)*val; return rt;}
int m=l+r>>1;
if(m>=L) ls[rt]=update(ls[pre],L,R,val,lson);
if(m<R) rs[rt]=update(rs[pre],L,R,val,rson);
sum[rt]=sum[ls[rt]]+sum[rs[rt]]+1ll*lazy[rt]*(r-l+1);
return rt;
}
long long query(int tim,int L,int R,int l,int r,long long tp){
if(L<=l&&R>=r) return sum[tim]+tp*(r-l+1);
int m=(l+r)/2;
long long ans=0;
if(m>=L) ans+=query(ls[tim],L,R,lson,tp+lazy[tim]);
if(m<R) ans+=query(rs[tim],L,R,rson,tp+lazy[tim]);
return ans;
}
int main(){
while(scanf("%d%d",&n,&q)!=EOF){
cnt=1; t=0;
for(int i=1;i<=n;i++)
scanf("%d",&arr[i]);
root[0]=build(1,n);
while(q--){
char ta[10];
scanf("%s",ta);
if(ta[0]=='Q'){
int l,r; scanf("%d%d",&l,&r);
printf("%lld\n",query(root[t],l,r,1,n,0));
}
else if(ta[0]=='C'){
int l,r,d; scanf("%d%d%d",&l,&r,&d);
root[t+1]=update(root[t],l,r,d,1,n);
t++;
}
else if(ta[0]=='H'){
int l,r,tb; scanf("%d%d%d",&l,&r,&tb);
printf("%lld\n",query(root[tb],l,r,1,n,0));
}
else{
int tb; scanf("%d",&tb);
if(t!=tb){t=tb; cnt=root[t+1]-1;}
}
}
}
}