hdu4348 To the moon

地址: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.
 

 

Input
n m
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\n",query(rt[k],1,n,l,r,0));
62             else if(op[0]=='H')
63                 scanf("%d%d%d",&l,&r,&d),printf("%I64d\n",query(rt[d],1,n,l,r,0));
64             else
65                 scanf("%d",&k);
66         }
67     }
68     return 0;
69 }

 

posted @ 2017-05-31 14:41  weeping  阅读(183)  评论(0编辑  收藏  举报