【HDU4348】【主席树】To the moon

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

2012 Multi-University Training Contest 5

【分析】

简单题,唯一要注意的是内存大小...

写指针各种被卡....无奈最后写数组...

看到有人用可持久化树状数组做...我开始算了一下好像会超内存,然后就没写了。。Orzzz

  1 /*
  2 唐代高蟾
  3 《金陵晚望》
  4
  5 曾伴浮云归晚翠,犹陪落日泛秋声。
  6 世间无限丹青手,一片伤心画不成。
  7 */
  8 #include <iostream>
  9 #include <cstdio>
 10 #include <algorithm>
 11 #include <cstring>
 12 #include <vector>
 13 #include <utility>
 14 #include <iomanip>
 15 #include <string>
 16 #include <cmath>
 17 #include <queue>
 18 #include <assert.h>
 19 #include <map>
 20 #include <ctime>
 21 #include <cstdlib>
 22 #include <stack>
 23 #define LOCAL
 24 const int MAXN = 3000000 + 10;
 25 const int MAXM = 1000000 + 10;
 26 const int INF = 100000000;
 27 const int SIZE = 450;
 28 const int maxnode =  0x7fffffff + 10;
 29 using namespace std;
 30 typedef long long ll;
 31 int lson[MAXN], rson[MAXN];
 32 int data[MAXN], add[MAXN];
 33 ll sum[MAXN];
 34 int tot;
 35
 36
 37 int insert(int t, int ll, int rr, int d, int l, int r){
 38     int now = ++tot;
 39     lson[now] = lson[t];
 40     rson[now] = rson[t];
 41     add[now] = add[t];
 42     sum[now] = sum[t];
 43     sum[now] += (long long)(d * (rr - ll + 1));
 44     if(ll == l && rr == r){
 45         add[now] += d;
 46         return now;
 47     }
 48     int mid = (l + r)>>1;
 49     if(rr <= mid) lson[now] = insert(lson[t], ll, rr, d, l, mid);
 50     else if(ll > mid) rson[now] = insert(rson[t], ll, rr, d, mid + 1, r);
 51     else{
 52         lson[now] = insert(lson[t], ll, mid, d, l, mid);
 53         rson[now] = insert(rson[t], mid + 1, rr, d, mid + 1, r);
 54     }
 55     return now;
 56 }
 57 //在t的根内查询[ll, rr]区间的值
 58 long long query(int t, int ll, int rr, int l, int r){
 59    long long Ans = (long long)(add[t] * (rr - ll + 1));
 60    if (ll == l && rr == r) return sum[t];
 61    int mid = (l + r)>>1;
 62    if (rr <= mid) Ans += query(lson[t], ll, rr, l, mid);
 63    else if (ll > mid) Ans += query(rson[t], ll, rr, mid + 1, r);
 64    else {
 65         Ans += query(lson[t], ll, mid, l, mid);
 66         Ans += query(rson[t], mid + 1, rr, mid + 1, r);
 67    }
 68    return Ans;
 69 }
 70 int build(int ll, int rr){
 71     int now = ++tot;
 72     add[now] = 0;
 73     if (ll == rr){
 74        scanf("%lld", &sum[now]);
 75        lson[now] = rson[now] = 0;
 76        return now;
 77     }
 78     int mid = (ll + rr)>>1;
 79     lson[now] = build(ll, mid);
 80     rson[now] = build(mid + 1, rr);
 81     sum[now] = sum[lson[now]] + sum[rson[now]];
 82     return now;
 83 }
 84
 85 int n ,m;
 86 void work(){
 87      tot = 0;
 88      data[0] = build(1,n);
 89      int now = 0;
 90      for (int i = 1; i <= m; i++){
 91          char str[3];
 92          scanf("%s", str);
 93          if (str[0] == ‘Q‘){
 94             int l, r;
 95             scanf("%d%d", &l, &r);
 96             printf("%lld\n", query(data[now], l, r, 1, n));
 97          }else if(str[0] == ‘C‘){
 98                int l, r, d;
 99                scanf("%d%d%d", &l, &r, &d);
100                data[now+1] = insert(data[now], l, r, d, 1, n);
101                now++;
102          }else if(str[0] == ‘H‘){
103                int l, r, t;
104                scanf("%d%d%d", &l, &r, &t);
105                printf("%lld\n", query(data[t], l, r, 1, n));
106          }else scanf("%d", &now);
107      }
108      printf("\n");
109 }
110
111 int main(){
112
113     while (scanf("%d%d", &n, &m) != EOF){
114           //scanf("%d%d", &n, &m);
115           work();
116     }
117     return 0;
118 }

时间: 2024-12-12 12:49:01

【HDU4348】【主席树】To the moon的相关文章

[HDU4348]To the moon(主席树+标记永久化)

学可持久化treap的时候才发现自己竟然没写过需要标记下传的主席树,然而现在发现大部分操作都可以标记永久化,下传会增大占用空间. 这题一种写法是和普通的线段树一样标记下传,注意所有修改操作(包括put())都要新建点.于是MLE了. 1 #include<cstdio> 2 #include<algorithm> 3 #define lson v[x].ls,L,mid 4 #define rson v[x].rs,mid+1,R 5 #define rep(i,l,r) for

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(主席树区间更新)

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

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(主席树 区间更新)题解

题意: 给一个数组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

[填坑]主席树

首先,可持久化数据结构,CLJ的论文里有讲. 通俗点来讲,就是该数据结构保留历史版本信息,对应的有可持久化链表,可持久化线段树,可持久化树状数组.比如对于线段树更新操作,每次更新新建一棵线段树,那么就有任意一次时间点信息. 当然,这样就非常耗空间,所以,对于线段树,每次只需要对于有更新的节点新建节点,否者可以用前一个版本的顶点(就是连接一下左右孩子就行了),这样,如果每次都是单点更改的话每次也就更改logn个点,空间复杂度nlogn. 接下来我们讲讲什么是主席树(orz 主席). 如果我的理解没

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ 3551】[ONTAK2010] Peaks加强版 Kruskal重构树+树上倍增+主席树

这题真刺激...... I.关于Kruskal重构树,我只能开门了,不过补充一下那玩意还是一棵满二叉树.(看一下内容之前请先进门坐一坐) II.原来只是用树上倍增求Lca,但其实树上倍增是一种方法,Lca只是他的一种应用,他可以搞各种树上问题,树上倍增一般都会用到f数组. |||.我们跑出来dfs序就能在他的上面进行主席树了. IV.别忘了离散. V.他可能不连通,我一开始想到了,但是我觉得出题人可能会是好(S)人(B),但是...... #include <cstdio> #include

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3207 给出一个长度为\(n\)的串,以及\(m\)个长度为\(k\)的串,求每个长度为\(k\)的串在原串\([x,y]\)区间是否出现过. 分析 这道题要求对比长度为\(k\)的串,于是我们把这些串的Hash值都算出来,问题就转化成了求\([x,y]\)的区间中是否出现过某Hash值. 求区间中某一个值出现了多少次,可以用主席树. p.s. 1.学习了主席树指针的写法,比数组慢好多啊...