hdu 4348 To the moon

题意:n个数 m次操作
操作分别为
C l r d: 把区间[l, r] 加 d
Q l r : 查询区间[l, r]的和
H l r t: 查询时间t的时候[l, r]的和
B t: 回到时间t

思路:主席树区间修改,区间求和

  1 const int maxn = 100000 + 10;
  2 const int maxnode = 25 * maxn;
  3
  4 int n, m;
  5
  6 struct Node
  7 {
  8     int l, r;
  9     LL sum, add;
 10 } tr[maxnode];
 11 int tail;
 12 LL a[maxn];
 13 LL qL, qR, value;
 14 LL sum;
 15
 16 #define lson tr[o].l,L,M
 17 #define rson tr[o].r,M+1,R
 18 #define self o,L,R
 19 #define lc tr[o].l
 20 #define rc tr[o].r
 21
 22 void build(int o, int L, int R)
 23 {
 24     if (L == R)
 25     {
 26         tr[o].sum = a[L];
 27         return;
 28     }
 29     tr[o].l = ++tail;
 30     tr[o].r = ++tail;
 31     int M = L + (R - L) / 2;
 32     build(lson);
 33     build(rson);
 34     tr[o].sum = tr[lc].sum + tr[rc].sum;
 35 }
 36
 37 void maintain(int o, int L, int R)
 38 {
 39     if (L < R)
 40     {
 41         tr[o].sum = tr[lc].sum + tr[rc].sum;
 42     }
 43     else tr[o].sum = a[L];
 44     tr[o].sum += tr[o].add * (R - L + 1);
 45 }
 46
 47 void update(int& o, int L, int R)
 48 {
 49     tr[++tail] = tr[o];
 50     o = tail;
 51     if (qL <= L && R <= qR)
 52     {
 53         tr[o].add += value;
 54     }
 55     else
 56     {
 57         int M = L + (R - L) / 2;
 58         if (qL <= M) update(lson);
 59         if (qR > M) update(rson);
 60     }
 61     maintain(self);
 62 }
 63
 64 void query(int o, int L, int R, int add)
 65 {
 66     if (qL <= L && R <= qR)
 67     {
 68         sum += tr[o].sum + add * (R - L + 1);
 69         return;
 70     }
 71     int M = L + (R - L) / 2;
 72     if (qL <= M) query(lson, add + tr[o].add);
 73     if (qR > M)  query(rson, add + tr[o].add);
 74 }
 75
 76 int root[maxn];//表示第i个线段树的root是什么,显然root[0]=0
 77
 78 void init()
 79 {
 80     memset(tr, 0, sizeof(tr));
 81     tail = 0;
 82     for (int i = 1; i <= n; i++)
 83     {
 84         scanf("%lld", &a[i]);
 85     }
 86     root[0] = 0;
 87     build(0, 1, n);
 88 }
 89
 90 void solve()
 91 {
 92     char op[5];
 93     int t;
 94     int i = 0;
 95     while (m--)
 96     {
 97         op[0] = 0;
 98         scanf("%s", op);
 99         if (op[0] == ‘Q‘)
100         {
101             scanf("%lld%lld", &qL, &qR);
102             sum = 0;
103             query(root[i], 1, n, 0);
104             printf("%lld\n", sum);
105
106         }
107         else if (op[0] == ‘C‘)
108         {
109             i++;
110             root[i] = root[i-1];
111             scanf("%lld%lld%lld", &qL, &qR, &value);
112             update(root[i], 1, n);
113         }
114         else if (op[0] == ‘H‘)
115         {
116             scanf("%lld%lld%d", &qL, &qR, &t);
117             sum = 0;
118             query(root[t], 1, n, 0);
119             printf("%lld\n", sum);
120         }
121         else
122         {
123             scanf("%d", &t);
124             i = t;
125         }
126     }
127 }
128
129 int main()
130 {
131     while (scanf("%d%d", &n, &m) == 2)
132     {
133         init();
134         solve();
135     }
136     return 0;
137 }
时间: 2024-11-09 06:32:21

hdu 4348 To the moon的相关文章

hdu 4348 To the moon(主席树区间操作)

题目链接:hdu 4348 To the moon 题意: 给你n个数,有m个操作. 1.给区间[l,r]的所有数+d,并且时间戳+1 2.询问当前时间戳的区间和. 3.询问过去时间戳t的区间和. 4.退回到时间戳t. 题解: 直接上主席树. 不过区间操作的时候push_down空间似乎不是那么够用. 所有把push_down这个操作去掉. 用一个标记记录当前这个区间的累加. 询问的时候就将这个累加传下去.(具体看代码) 最后还有退回状态t的时候可以把cnt=root[t+1], 因为后面的内存

hdu 4348 To the moon (主席树)

hdu 4348 题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q l r:查询当前时间戳区间[l,r]中所有数的和 . (3)H l r t:查询时间戳t区间[l,r]的和 . (4)B t:将当前时间戳置为t . 所有操作均合法 . 解法: 很明显是一道主席树的题 . 对于每一次区间加法都新建节点建一棵线段树,加个懒惰标记就行了,查询的话直接线段树区间求和 . 不过感觉这一题就是为可持续化数据结构写的,特别是时间戳

HDU 4348 To the moon 可持久化线段树

To the moon Problem Description BackgroundTo 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 reco

HDU - 4348 To the moon(主席树区间更新)

题目链接:To the moon 题意:给个数组,三种操作,第一种询问当前区间[l,r]的和,第二种给区间[l,r]的每一个数加上d,第三种询问在第几次修改后[l,r]的权值 题解:如果这题只询问区间和更新,简单建棵线段树维护区间和用延时标记就可以了,但是它询问第几次修改之后一段区间的值,这样的话刚才的方法就不好用,那我们可不可以,在每次修改之后的重新建一棵线段树呢?直接重新建的话空间会爆,这个时候就可以用??币的主席树(没学过主席树可以先做一下这个),每次的修改只会再新增logN个节点,先把给

HDU 4348 To the moon(主席树 区间更新)题解

题意: 给一个数组A[1] ~ A[n],有4种操作: Q l r询问l r区间和 C l r v给l r区间每个数加v H l r t询问第t步操作的时候l r区间和 B t返回到第t步操作 思路: 用主席树维护常规的线段树.我们之前已经知道了主席树单点更新,只要新增一条链就ok了,区间更新也有点差不多.我们每次要更新都用一个lazy标记,但是显然我们不能去更新那些已经存在的区间,那么我们就新建出所有要更新的区间.因为可持久化线段树有些结点不是自己的,所以我们不能直接简单的push up和pu

HDU 4348 / SPOJ TTM - To the moon

终于过了..感谢xiaodao提供测试数据,然后最终找到了一个十分ruozhi的BUG...= =,坑爹..没什么好说的,直接上主席树的干活...下面是HDU的代码,如果是SPOJ自行把%I64d换成%lld继续干活.. 1 /* 2 ID:esxgx1 3 LANG:C++ 4 PROG:hdu4348 5 */ 6 #include <cassert> 7 #include <cstdio> 8 #include <cstring> 9 #include <i

HDU 4348 I - To the moon 可持续化

队友用的可持续化线段树,徘徊在RE和MLE之间多发过的... 看见这种题,我的第一反应是离线询问,按照时间顺序组织操作然后dfs. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <vector> using namespace std; const int maxn = 10

【HDOJ】4348 To the moon

主席树区间更新,延迟标记. 1 /* 4348 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque>

主席树 hdu 4348

题意:有一个由n个数组成的序列,有4中操作: 1.C l r d [l,r]这段区间都加上d 2.Q l r 询问[l,r]这段区间的和 3.H l r t 询问之前t时间[l,r]的区间和 4.B t 回到t时间,且下一秒的时间从t开始 按时间建立主席树,主席树上的每一棵线段树维护[1,n]这段序列的信息,这里成段更新的时候要注意,以往写线段树的时候,都是把lazy标记向下传,但是写主席树的时候每一次下传,那么新的节点数就会非常多,会爆内存,所以我们不把lazy操作下传,只是在询问的时候,最后