1. 程式人生 > >hdu 4348 To the moon (主席樹 區間更新)

hdu 4348 To the moon (主席樹 區間更新)

tac pri tle uil 寫法 += pragma 需要 當前時間

鏈接: 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\n",query(x,y,1,n,root[tim])); } else if(op[0] == H){ int t; scanf("%d%d%d",&x,&y,&t); printf("%lld\n",query(x,y,1,n,root[t])); } else if(op[0] == B){ scanf("%d",&x); tim = x; } } } return 0; }

hdu 4348 To the moon (主席樹 區間更新)