[HDU4348]To the moon(主席树+标记永久化)
学可持久化treap的时候才发现自己竟然没写过需要标记下传的主席树,然而现在发现大部分操作都可以标记永久化,下传会增大占用空间。
这题一种写法是和普通的线段树一样标记下传,注意所有修改操作(包括put())都要新建点。于是MLE了。
1 #include<cstdio> 2 #include<algorithm> 3 #define lson v[x].ls,L,mid 4 #define rson v[x].rs,mid+1,R 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=100010; 10 char op; 11 int n,m,l,r,k,tim,nd,a[N],rt[N]; 12 struct Tr{ int ls,rs; ll sm,tag; }v[N*25]; 13 14 void put(int &x,int L,int R,ll k){ if (x) v[++nd]=v[x],x=nd,v[nd].sm+=(R-L+1)*k,v[nd].tag+=k; } 15 16 void push(int x,int L,int R){ int mid=(L+R)>>1; if (v[x].tag) put(lson,v[x].tag),put(rson,v[x].tag),v[x].tag=0; } 17 18 void build(int &x,int L,int R){ 19 x=++nd; 20 if (L==R){ v[x]=(Tr){0,0,a[L],0}; return; } 21 int mid=(L+R)>>1; 22 build(lson); build(rson); 23 v[x].sm=v[v[x].ls].sm+v[v[x].rs].sm; v[x].tag=0; 24 } 25 26 void ins(int y,int &x,int L,int R,int l,int r,int k){ 27 x=++nd; v[x]=v[y]; 28 if (L==l && r==R){ v[x].sm+=1ll*(R-L+1)*k; v[x].tag+=k; return; } 29 int mid=(L+R)>>1; push(x,L,R); 30 if (r<=mid) ins(v[y].ls,lson,l,r,k); 31 else if (l>mid) ins(v[y].rs,rson,l,r,k); 32 else ins(v[y].ls,lson,l,mid,k),ins(v[y].rs,rson,mid+1,r,k); 33 v[x].sm=v[v[x].ls].sm+v[v[x].rs].sm; 34 } 35 36 ll que(int x,int L,int R,int l,int r){ 37 if (L==l && r==R) return v[x].sm; 38 int mid=(L+R)>>1; push(x,L,R); 39 if (r<=mid) return que(lson,l,r); 40 else if (l>mid) return que(rson,l,r); 41 else return que(lson,l,mid)+que(rson,mid+1,r); 42 } 43 44 int main(){ 45 freopen("hdu4348.in","r",stdin); 46 freopen("hdu4348.out","w",stdout); 47 while (~scanf("%d%d",&n,&m)){ 48 rep(i,1,n) scanf("%d",&a[i]); 49 nd=tim=0; build(rt[0],1,n); 50 rep(i,1,m){ 51 scanf(" %c",&op); 52 if (op=='C') scanf("%d%d%d",&l,&r,&k),tim++,ins(rt[tim-1],rt[tim],1,n,l,r,k); 53 if (op=='Q') scanf("%d%d",&l,&r),printf("%lld\n",que(rt[tim],1,n,l,r)); 54 if (op=='H') scanf("%d%d%d",&l,&r,&k),printf("%lld\n",que(rt[k],1,n,l,r)); 55 if (op=='B') scanf("%d",&k),tim=k; 56 } 57 puts(""); 58 } 59 return 0; 60 }
另一种写法就是标记永久化,若一个修改区间覆盖当前区间则将tag+=k,但并不下传。询问时将答案加上tag的贡献即可。
注意多组数据的清空问题。
1 #include<cstdio> 2 #include<algorithm> 3 #define lson v[x].ls,L,mid 4 #define rson v[x].rs,mid+1,R 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=100010; 10 char op; 11 int n,m,l,r,k,tim,nd,flag,a[N],rt[N]; 12 struct Tr{ int ls,rs; ll sm,tag; }v[N*25]; 13 14 void build(int &x,int L,int R){ 15 x=++nd; 16 if (L==R){ v[x]=(Tr){0,0,a[L],0}; return; } 17 int mid=(L+R)>>1; 18 build(lson); build(rson); 19 v[x].sm=v[v[x].ls].sm+v[v[x].rs].sm; v[x].tag=0; 20 } 21 22 void ins(int y,int &x,int L,int R,int l,int r,int k){ 23 x=++nd; v[x]=v[y]; v[x].sm+=1ll*(r-l+1)*k; 24 if (L==l && r==R){ v[x].tag+=k; return; } 25 int mid=(L+R)>>1; 26 if (r<=mid) ins(v[y].ls,lson,l,r,k); 27 else if (l>mid) ins(v[y].rs,rson,l,r,k); 28 else ins(v[y].ls,lson,l,mid,k),ins(v[y].rs,rson,mid+1,r,k); 29 } 30 31 ll que(int x,int L,int R,int l,int r){ 32 if (L==l && r==R) return v[x].sm; 33 int mid=(L+R)>>1,res=v[x].tag*(r-l+1); 34 if (r<=mid) return res+que(lson,l,r); 35 else if (l>mid) return res+que(rson,l,r); 36 else return res+que(lson,l,mid)+que(rson,mid+1,r); 37 } 38 39 int main(){ 40 freopen("hdu4348.in","r",stdin); 41 freopen("hdu4348.out","w",stdout); 42 while (~scanf("%d%d",&n,&m)){ 43 if (flag) puts(""); else flag=1; 44 rep(i,1,n) scanf("%d",&a[i]); 45 nd=tim=0; build(rt[0],1,n); 46 rep(i,1,m){ 47 scanf(" %c",&op); 48 if (op=='C') scanf("%d%d%d",&l,&r,&k),tim++,ins(rt[tim-1],rt[tim],1,n,l,r,k); 49 if (op=='Q') scanf("%d%d",&l,&r),printf("%lld\n",que(rt[tim],1,n,l,r)); 50 if (op=='H') scanf("%d%d%d",&l,&r,&k),printf("%lld\n",que(rt[k],1,n,l,r)); 51 if (op=='B') scanf("%d",&tim); 52 } 53 } 54 return 0; 55 }