HDU4348:To the moon
浅谈主席树:https://www.cnblogs.com/AKMer/p/9956734.html
浅谈标记永久化:https://www.cnblogs.com/AKMer/p/10137227.html
题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4348
相比一般的主席树,这个要多支持一个操作,那就是区间修改。我们不能把区间里的每一条链都建出来,因为那样时间空间都不允许,所以我们可以依靠标记永久化来实现。每次询问的时候,把一路上的标记全部累加起来,再计算对当前区间答案的影响就好了。
时间复杂度:\(O((n+m)logn)\)
空间复杂度:\(O((n+m)logn)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
char s[10];
int n,m,tim;
int a[maxn],rt[maxn];
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct tree_node {
ll sum;
int ls,rs,tag;
};
struct Chairman_tree {
int tot;
tree_node tree[maxn*30];
void updata(int p) {
tree[p].sum=tree[tree[p].ls].sum+tree[tree[p].rs].sum;
}
void build(int &now,int l,int r) {
now=++tot;tree[now].tag=0;
if(l==r) {
tree[now].sum=a[l];
tree[now].ls=tree[now].rs=0;
return;
}
int mid=(l+r)>>1;
build(tree[now].ls,l,mid);
build(tree[now].rs,mid+1,r);
updata(now);
}
void change(int lst,int &now,int l,int r,int L,int R,int v) {
now=++tot;tree[now]=tree[lst];
tree[now].sum+=1ll*(min(r,R)-max(l,L)+1)*v;//记得要一路修改下去
//如果调用updata函数用儿子节点更新自己的值,可能会用没被标记影响的上一个版本的主席树的儿子来更新自己
if(L<=l&&r<=R) {
tree[now].tag+=v;
return;
}
int mid=(l+r)>>1;
if(L<=mid)change(tree[lst].ls,tree[now].ls,l,mid,L,R,v);
if(R>mid)change(tree[lst].rs,tree[now].rs,mid+1,r,L,R,v);
}
ll query(int now,int l,int r,int L,int R,int res) {
if(L<=l&&r<=R)return tree[now].sum+1ll*(r-l+1)*res;
int mid=(l+r)>>1;ll val=0;
if(L<=mid)val+=query(tree[now].ls,l,mid,L,R,res+tree[now].tag);
if(R>mid)val+=query(tree[now].rs,mid+1,r,L,R,res+tree[now].tag);
return val;
}
}T;
int main() {
while(~scanf("%d%d",&n,&m)) {
tim=T.tot=0;
for(int i=1;i<=n;i++)
a[i]=read();
T.build(rt[0],1,n);
for(int i=1;i<=m;i++) {
scanf("%s",s+1);
if(s[1]=='C') {
tim++;int l=read(),r=read(),d=read();
T.change(rt[tim-1],rt[tim],1,n,l,r,d);
}
else if(s[1]=='Q') {
int l=read(),r=read();
ll ans=T.query(rt[tim],1,n,l,r,0);
printf("%lld\n",ans);
}
else if(s[1]=='H') {
int l=read(),r=read(),t=read();
ll ans=T.query(rt[t],1,n,l,r,0);
printf("%lld\n",ans);
}
else if(s[1]=='B') {
int t=read();
tim=t;T.tot=rt[tim+1];
}
}
}
return 0;
}