【HDU - 4348】To the moon(主席树,区间更新)
題干:
Background?
To The Moon is a independent game released in November 2011, it is a role-playing adventure game powered by RPG Maker.?
The premise of To The Moon is based around a technology that allows us to permanently reconstruct the memory on dying man. In this problem, we'll give you a chance, to implement the logic behind the scene.?
You‘ve been given N integers A?[1], A?[2],..., A?[N]. On these integers, you need to implement the following operations:?
1.?C l r d: Adding a constant d for every {A?i?| l <= i <= r}, and increase the time stamp by 1, this is the only operation that will cause the time stamp increase.?
2.?Q l r: Querying the current sum of {A?i?| l <= i <= r}.?
3.?H l r t: Querying a history sum of {A?i?| l <= i <= r} in time t.?
4.?B t: Back to time t. And once you decide return to a past, you can never be access to a forward edition anymore.?
.. N, M ≤ 10?5, |A?[i]| ≤ 10?9, 1 ≤ l ≤ r ≤ N, |d| ≤ 10?4?.. the system start from time 0, and the first modification is in time 1, t ≥ 0, and won't introduce you to a future state.
Input
n m?
A?1?A?2?... A?n?
... (here following the m operations. )
Output
... (for each query, simply print the result. )
Sample Input
10 5 1 2 3 4 5 6 7 8 9 10 Q 4 4 Q 1 10 Q 2 4 C 3 6 3 Q 2 42 4 0 0 C 1 1 1 C 2 2 -1 Q 1 2 H 1 2 1Sample Output
4 55 9 150 1題目大意:
1. 將l到r之間所有的數+d,同時時間戳+1。 2. 查詢當前時間戳下l到r的所有數的總和。 3..查詢時間戳d下的l到r的所有數的和。 4.將時間戳返回至t。
解題報告:
因為涉及到主席樹的區間操作,所以肯定要lazy標記,但是下傳的時候,如果按照線段樹的寫法直接照搬過來,那需要pushdown操作,也就是說涉及到了兩個孩子節點的修改,也就是說需要動態開兩個節點,然后分別遞歸下去。這樣的話最差復雜度和建n棵線段樹應該是同階的。
考慮優化這個節點太多的問題,既然是下傳標記使得需要修改的節點數增多,那么嘗試不下傳標記?發現可以將標記留在節點上,查詢時往下遞歸的過程遇到lazy則累加就行了,最后把標記的影響加到總答案里。(想了想感覺線段樹其實也可以這么干,只不過在pushup的時候比較麻煩就是了,詳見下一段)
注意這個題的pushup函數也要改,因為你.val代表的是當前節點及其孩子節點的正確的值,但是不一定等于兩個孩子節點的val值的和,因為還有cur中沒有下傳的lazy標記,也要算進去。
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<set> #include<string> #include<cmath> #include<cstring> #define FF first #define SS second #define ll long long #define pb push_back #define pm make_pair using namespace std; typedef pair<int,int> PII; const int MAX = 1e5 + 5; struct TREE {int l,r;ll val,lazy; } tr[MAX*40];int tot; int a[MAX]; int root[MAX]; void pushup(int cur,int l,int r) {tr[cur].val = tr[tr[cur].l].val + tr[tr[cur].r].val + tr[cur].lazy*(r-l+1); } int build(int l,int r) {int cur = ++tot;tr[cur].lazy = 0;if(l == r) {tr[cur].val = a[l];//這一步好像沒啥用? return cur;}int m = (l+r)>>1;tr[cur].l = build(l,m);tr[cur].r = build(m+1,r);pushup(cur,l,r);return cur; } int update(int pre,int pl,int pr,ll val,int l,int r) {int cur = ++tot;tr[cur] = tr[pre];if(pl <= l && pr >= r) {tr[cur].val += (r-l+1)*val;tr[cur].lazy += val;return cur;}int m = (l+r)>>1;if(pl <= m) tr[cur].l = update(tr[pre].l,pl,pr,val,l,m);if(pr >= m+1) tr[cur].r = update(tr[pre].r,pl,pr,val,m+1,r);pushup(cur,l,r);return cur; } ll query(int cur,int pl,int pr,ll laz,int l,int r) {if(pl <= l && pr >= r) return tr[cur].val + laz * (r-l+1);ll res = 0;laz += tr[cur].lazy;int m = (l+r)>>1; if(pl <= m) res += query(tr[cur].l,pl,pr,laz,l,m);if(pr >= m+1) res += query(tr[cur].r,pl,pr,laz,m+1,r); return res; } int main() {int n,m,l,r;ll d;char op[5];while(cin>>n>>m) {for(int i = 1; i<=n; i++) cin>>a[i];int T = 0,t; tot=0;root[T] = build(1,n);while(m--) {scanf("%s",op);if(op[0] == 'C') {scanf("%d%d%lld",&l,&r,&d);T++;root[T] = update(root[T-1],l,r,d,1,n);//注意這里的序列是1~n就行了,而不是1~m!!! }else if(op[0] == 'Q') {scanf("%d%d",&l,&r);printf("%lld\n",query(root[T],l,r,0,1,n));}else if(op[0] == 'H') {scanf("%d%d%d",&l,&r,&t);printf("%lld\n",query(root[t],l,r,0,1,n));}else scanf("%d",&T); } }return 0 ; } /* 2 4 0 0 C 1 1 1 C 2 2 -1 Q 1 2 H 1 2 1 */?
總結
以上是生活随笔為你收集整理的【HDU - 4348】To the moon(主席树,区间更新)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ssgrate.exe - ssgrat
- 下一篇: sshd.exe - sshd进程是什么