给一个序列,有4种操作。
1. 从l到r区间增加d,并让时间戳+1
2. 查询l到r的区间和
3. 查询在t时刻的l到r的区间和
4. 将整个序列回退到t时刻的状态
可持久化线段树...直接做就好..虽然理论上会爆内存..但是实际上由于数据比较水..所以没用到那么多节点..
#include <cstdio>
struct SeqNode {
SeqNode *ls,*rs;
long long sum;
int lazy;
};
SeqNode b[7000000],*bp;
SeqNode *root[100000];
int n,m;
SeqNode *makeTree(int l,int r) {
SeqNode *ans=bp++;
ans->lazy=0;
if (l==r) {
ans->ls=ans->rs=NULL;
scanf("%lld",&ans->sum);
} else {
int t=(l+r)/2;
ans->ls=makeTree(l,t);
ans->rs=makeTree(t+1,r);
ans->sum=ans->ls->sum+ans->rs->sum;
}
return ans;
}
SeqNode *set(SeqNode *from,int l,int r,int ll,int rr,int x) {
SeqNode *ans=bp++;
*ans=*from;
ans->sum+=(rr-ll+1)*x;
if (l==ll&&r==rr) {
ans->lazy+=x;
} else {
int t=(l+r)/2;
if (rr<=t) ans->ls=set(from->ls,l,t,ll,rr,x);
else if (ll>t) ans->rs=set(from->rs,t+1,r,ll,rr,x);
else {
ans->ls=set(from->ls,l,t,ll,t,x);
ans->rs=set(from->rs,t+1,r,t+1,rr,x);
}
}
return ans;
}
long long get(SeqNode *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr) return from->sum;
int t=(l+r)/2;
long long ans=(rr-ll+1)*from->lazy;
if (rr<=t) ans+=get(from->ls,l,t,ll,rr);
else if (ll>t) ans+=get(from->rs,t+1,r,ll,rr);
else {
ans+=get(from->ls,l,t,ll,t);
ans+=get(from->rs,t+1,r,t+1,rr);
}
return ans;
}
int main() {
int i,t;
while (scanf("%d%d",&n,&m)!=EOF) {
bp=b;
root[0]=makeTree(1,n);
t=1;
for (i=0;i<m;i++) {
char c;
int l,r,d,x;
scanf(" %c",&c);
if (c=='C') {
scanf("%d%d%d",&l,&r,&d);
root[t]=set(root[t-1],1,n,l,r,d);
t++;
} else if (c=='Q') {
scanf("%d%d",&l,&r);
printf("%lld\n",get(root[t-1],1,n,l,r));
} else if (c=='H') {
scanf("%d%d%d",&l,&r,&x);
printf("%lld\n",get(root[x],1,n,l,r));
} else if (c=='B') {
scanf("%d",&x);
t=x+1;
}
}
}
return 0;
}