题意:
思路:
每次修改,就新开一个树,如果大小是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;}}}}
}