地址:http://acm.hdu.edu.cn/showproblem.php?pid=4348
题目:
To the moon
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 5374 Accepted Submission(s): 1232
Problem Description
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 {Ai | 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 {Ai | l <= i <= r}.
3. H l r t: Querying a history sum of {Ai | 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 ≤ 105, |A[i]| ≤ 109, 1 ≤ l ≤ r ≤ N, |d| ≤ 104 .. 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.
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 {Ai | 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 {Ai | l <= i <= r}.
3. H l r t: Querying a history sum of {Ai | 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 ≤ 105, |A[i]| ≤ 109, 1 ≤ l ≤ r ≤ N, |d| ≤ 104 .. 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
A1 A2 ... An
... (here following the m operations. )
A1 A2 ... An
... (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 4
2 4
0 0
C 1 1 1
C 2 2 -1
Q 1 2
H 1 2 1
Sample Output
4
55
9
15
0
1
Author
HIT
Source
思路:
持久化线段树:每次根据前一个版本建树,遇到要修改的区间就新增加节点,不修改的沿用前一版本的节点。
怎么区间修改呢?
打标记即可,但标记不要下传!否则空间复杂度会炸。
那怎么办?
在修改时经过的所有区间需要维护修改后的区间和,修改标记打在被整段覆盖的区间上。
标记不下传,那查询怎么办?
查询到一个区间时,把之前的遇到的区间的标记求和,答案就是标记和乘以区间长度+这个区间的区间和。
1 #include <bits/stdc++.h>
2
3 using namespace std;
4
5 #define MP make_pair
6 #define PB push_back
7 typedef long long LL;
8 typedef pair<int,int> PII;
9 const double eps=1e-8;
10 const double pi=acos(-1.0);
11 const int K=5e6+7;
12 const int mod=1e9+7;
13
14 int tot,ls[K],rs[K],rt[K];
15 LL sum[K],add[K],v[K];
16 //sum[o]记录的是该节点区间内出现的数的个数
17 //区间指的是将数离散化后的区间
18 void build(int &o,int l,int r)
19 {
20 o=tot++,sum[o]=v[l],add[o]=0;
21 if(l==r) return ;
22 int mid=l+r>>1;
23 build(ls[o],l,mid),build(rs[o],mid+1,r);
24 sum[o]=sum[ls[o]]+sum[rs[o]];
25 }
26 void update(int &o,int p,int l,int r,int nl,int nr,LL x)
27 {
28 o=tot++,ls[o]=ls[p],rs[o]=rs[p],sum[o]=sum[p]+(nr-nl+1)*x,add[o]=add[p];
29 if(l==nl && r==nr){add[o]+=x;return;}
30 int mid=l+r>>1;
31 if(nr<=mid) update(ls[o],ls[p],l,mid,nl,nr,x);
32 else if(nl>mid) update(rs[o],rs[p],mid+1,r,nl,nr,x);
33 else update(ls[o],ls[p],l,mid,nl,mid,x),update(rs[o],rs[p],mid+1,r,mid+1,nr,x);
34 sum[o]=sum[ls[o]]+sum[rs[o]]+(r-l+1)*add[o];
35 }
36 LL query(int o,int l,int r,int nl,int nr,LL f)
37 {
38 if(l==nl && r==nr) return sum[o]+(nr-nl+1)*f;
39 int mid=l+r>>1;
40 if(nr<=mid) return query(ls[o],l,mid,nl,nr,f+add[o]);
41 else if(nl>mid) return query(rs[o],mid+1,r,nl,nr,f+add[o]);
42 return query(ls[o],l,mid,nl,mid,f+add[o])+query(rs[o],mid+1,r,mid+1,nr,f+add[o]);
43 }
44 int main(void)
45 {
46 int n,m;
47 while(~scanf("%d%d",&n,&m))
48 {
49 tot=0;
50 for(int i=1;i<=n;i++)
51 scanf("%I64d",v+i);
52 build(rt[0],1,n);
53 int k=0,l,r,d;
54 char op[10];
55 while(m--)
56 {
57 scanf("%s",op);
58 if(op[0]=='C')
59 scanf("%d%d%d",&l,&r,&d),update(rt[k+1],rt[k],1,n,l,r,d),k++;
60 else if(op[0]=='Q')
61 scanf("%d%d",&l,&r),printf("%I64d
",query(rt[k],1,n,l,r,0));
62 else if(op[0]=='H')
63 scanf("%d%d%d",&l,&r,&d),printf("%I64d
",query(rt[d],1,n,l,r,0));
64 else
65 scanf("%d",&k);
66 }
67 }
68 return 0;
69 }