hdu 4348 To the moon (主席树 区间更新)
Posted kls123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 4348 To the moon (主席树 区间更新)相关的知识,希望对你有一定的参考价值。
链接: http://acm.hdu.edu.cn/showproblem.php?pid=4348
题意:
4种操作:
C l r c 区间[l,r]加c,时间+1
Q l r 询问当前时间区间[l,r]的和
H l r c 询问在时间t时,区间[l,r]的和
B x 回到时间x
思路:
涉及历史版本的询问,很容易想到主席树,然后尝试用线段树的思路用主席树写了下,疯狂WA,TLE,后面看了下其他人的博客。。。。发现不能加pushdown操作,因为一般来说pushdown更新完当前点后会向下更新子树,这样会新增很多点,其实我们可以将向下更新子树的操作省略,每次从根节点向下到需要的区间的过程中加上经过的点的lazy值就好了这样就实现了向下更新,且不会建过多的点。
还有因为计算从根到所求区间过程经过的标记数组对所求区间值的影响我们写法是:lazy*(R-L+1)所以查询操作没有用完全版线段树那种写法,换了一种,之前的写法,L,R,是不变的,但是我们是需要通过改变L,R,来表示当前标记数组作用的区间,需要改变L,R。
表达能力好弱啊。。。感觉讲不清楚想表达的思路。。。。难受
实现代码:、
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<bits/stdc++.h> using namespace std; #define ll long long const int M = 1e5+10; ll a[M],sum[M*40],lazy[M*40]; int ls[M*40],rs[M*40],root[M],idx; void pushup(int l,int r,int rt){ sum[rt] = sum[ls[rt]] + sum[rs[rt]] + 1LL*(r-l+1)*lazy[rt]; } void build(int l,int r,int &rt){ rt = ++idx;lazy[rt] = 0; sum[rt] = 0; if(l == r){ sum[rt] = a[l]; return ; } int m = (l + r) >> 1; build(l,m,ls[rt]); build(m+1,r,rs[rt]); pushup(l,r,rt); } void update(int old,int &rt,int L,int R,ll c,int l,int r){ rt = ++idx; ls[rt] = ls[old]; rs[rt] = rs[old]; sum[rt] = sum[old]; lazy[rt] = lazy[old]; if(L <= l&&R >= r){ sum[rt] += 1LL*(r-l+1)*c; lazy[rt] += c; return ; } int m = (l + r) >> 1; if(L <= m) update(ls[old],ls[rt],L,R,c,l,m); if(R > m) update(rs[old],rs[rt],L,R,c,m+1,r); pushup(l,r,rt); } ll query(int L,int R,int l,int r,int rt){ if(L <= l&&R >= r) return sum[rt]; int m = (l + r) >> 1; ll ans = 1LL*(R-L+1)*lazy[rt]; /* 这种写法是不对的 if(L <= m) ans += query(L,R,l,m,ls[rt]); if(R > m) ans += query(L,R,m+1,r,rs[rt]); */ //正确写法 if(R <= m) ans += query(L,R,l,m,ls[rt]); else if(L > m) ans += query(L,R,m+1,r,rs[rt]); else{ ans += query(L,m,l,m,ls[rt]); ans += query(m+1,R,m+1,r,rs[rt]); } return ans; } char op[3]; int main() { int n,q,x,y; ll z; while(scanf("%d%d",&n,&q)!=EOF){ idx = 0;memset(root,0,sizeof(root)); for(int i = 1;i <= n;i ++) scanf("%lld",&a[i]); build(1,n,root[0]); int tim = 0; for(int i = 1;i <= q;i ++){ scanf("%s",op); if(op[0] == ‘C‘){ scanf("%d%d%lld",&x,&y,&z); update(root[tim],root[tim+1],x,y,z,1,n); tim++; } else if(op[0] == ‘Q‘){ scanf("%d%d",&x,&y); printf("%lld ",query(x,y,1,n,root[tim])); } else if(op[0] == ‘H‘){ int t; scanf("%d%d%d",&x,&y,&t); printf("%lld ",query(x,y,1,n,root[t])); } else if(op[0] == ‘B‘){ scanf("%d",&x); tim = x; } } } return 0; }
以上是关于hdu 4348 To the moon (主席树 区间更新)的主要内容,如果未能解决你的问题,请参考以下文章
[HDU4348]To the moon(主席树+标记永久化)
HDU 4348 To the moon(主席树 区间更新)题解