[BZOJ]3489 A simple rmq problem 主席树套树
来源:互联网 发布:在手机上怎么开淘宝店 编辑:程序博客网 时间:2024/06/05 14:49
3489: A simple rmq problem
Time Limit: 40 Sec Memory Limit: 600 MB
Submit: 2074 Solved: 708
[Submit][Status][Discuss]
Description
因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
Input
第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N
再下面M行,每行两个整数x,y,
询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):
l=min((x+lastans)mod n+1,(y+lastans)mod n+1);
r=max((x+lastans)mod n+1,(y+lastans)mod n+1);
Lastans表示上一个询问的答案,一开始lastans为0
Output
一共M行,每行给出每个询问的答案。
Sample Input
10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9
Sample Output
4
10
10
0
0
10
0
4
0
4
HINT
注意出题人为了方便,input的第二行最后多了个空格。
2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测
Source
by zhzqkkk
题解
原来的编辑模式字体有毒改不过来啊... 这下粘题面就不能顺便粘走超链接. 只能用markdown了, 不过谁能告诉我markdown怎么行首空两格... Upd:现在会了.
不会K-D Tree怎么办… 不过话说K-D Tree不会被卡吗?
一开始在openjudge的cdqz小组里数据结构中看到此题, 不过那道题可以离线. 当时想了很久… 一开始觉得这道题非常的naive, 主席树搞一下就行了! 发现唯一出现实际上是一个三维关系.
三维关系分别是如果a[i]要对L到R的询问构成贡献, 那么pre[a[i]] < L, nxt[a[i]] > R, L <= i <= R. 所以说就可以转化为三维空间, 用K-D Tree即可, 只是本蒟蒻不会…. 但是K-D Tree很难卡但是也应该是能被卡的吧.
冥思苦想YY了一下树套树, 写了一发.
但是从来没学过没做过树套树啊!!一上来还想了个主席树套树, 真的是作死. 当时想着时间空间都是nlog^2n的, 十万能过, 没有想过实现的困难就写了. 搞了半个下午… (突然想起之前没有学过带修改莫队和树上莫队直接去做糖果公园… 自己zuo啊… 那道200s的题有一次T了, 卡了评测两页gg).
我们按pre排一下序, 这样sort可以消去一位.
用主席树对pre值序列维护. root[i]保存了所有pre在i位置及之前的所有数字的信息(先不管是什么信息, 反正满足原序列里pre在i之前的就会被记录进去). 然后对于root[i], L-R区间代表的是整棵root[i]保存数字中满足nxt在L-R的数字的信息. 这样就满足pre和nxt的限制了.
然后对于第三维, 我们就对于主席树的每个节点开一棵线段树, 这棵线段树的L-R保存的就是数字本身位置在L-R的信息, 这个信息就是这个数字的值. 这样就满足第三维了.
这样我们对于L-R的查询, 在root[L-1]里查, 满足查询的数字的pre < L. 再进入到root[L-1]的R+1-n区间中, 这样就满足了nxt>R(主席树即外层的树是以nxt为下标的). 然后在这个区间里的线段所套的线段树查L-R的保存的信息即数字本身值得最大值. 这样三维就满足了.
分析一下空间. 主席树动态开链, 构建主席树是每到一个位置i就会开一个log的链, 然后对于这条链上的每个节点开的线段树也动态开一条log链来保存i的信息, 这样就是log^2n的空间, 因为有n个位置, 所以是nlog^2n的空间.
分析一下时间. 每次查询R+1-n时间包含log个节点, 每个节点还要进入所套的线段树再查L-R的最大值, 所以每次查询nlog^2n的.
所以说可以过了~ 做出来还是成就满满. 但是openjudge的cdqz的那道练习过不去, 因为那道题n是300000而且空间只有512mb, bzoj有600mb… 于是乎MLE了.
但是cdqz那道题可以离线啊…前辈过的都写得K-D Tree, 但是想到可以离线转化成二维平面上的矩形单点查询, 扫描线nlog完美解决... 日后搞算几练扫描线的时候再去A那道题吧, 说不定艹榜... Upd:发现还是要nlog^n?
树套树代码不长, 常数有点大…(原来的代码风格的话不加读优可能就80多行)
#include<stdio.h>#include<algorithm>#define Acce register intusing namespace std;const int maxn = 1e5 + 5;const int maxm = 3e7 + 3e6;int n, m, l, r, ans, las, last[maxn];inline const int read(){ Acce x = 0; char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); return x;}struct point{ int v, pre, nxt, id; friend bool operator < (point x, point y) { return x.pre < y.pre; }}a[maxn];struct node{ int cmax; node *ls, *rs, *rt;}pool[maxm], *root[maxn], *null, *tail = pool;inline void init(){ null = ++ tail; null -> cmax = 0; null -> ls = null -> rs = null -> rt = null;}inline node* newnode(){ node* bt = ++ tail; bt -> ls = bt -> rs = bt -> rt = null; bt -> cmax = 0; return bt;}void modify(node* bt, node* pre, int lf, int rg, int pos, int val){ bt -> cmax = max(max(bt -> cmax, pre -> cmax), val); if (lf == rg) return; int mid = (lf + rg) >> 1; if (pos <= mid) { if(bt -> ls == null) bt -> ls = newnode(); if(bt -> rs == null) bt -> rs = pre -> rs; modify(bt -> ls, pre -> ls, lf, mid, pos, val); } else { if(bt -> rs == null) bt -> rs = newnode(); if(bt -> ls == null) bt -> ls = pre -> ls; modify(bt -> rs, pre -> rs, mid + 1, rg, pos, val); }}void insert(node* bt, node* pre, int lf, int rg, point x){ if(bt -> rt == null) bt -> rt = newnode(); modify(bt -> rt, pre -> rt, 1, n, x.id, x.v); if(lf == rg) return; int mid = (lf + rg) >> 1; if (x.nxt <= mid) { if (bt -> ls == null) bt -> ls = newnode(); if (bt -> rs == null) bt -> rs = pre -> rs; insert(bt -> ls, pre -> ls, lf, mid, x); } else { if (bt -> rs == null) bt -> rs = newnode(); if (bt -> ls == null) bt -> ls = pre -> ls; insert(bt -> rs, pre -> rs, mid + 1, rg, x); }}int query_cmax(node *bt, int lf, int rg, int L, int R){ if (L <= lf && rg <= R) return bt -> cmax; int rt1 = 0, rt2 = 0, mid = (lf + rg) >> 1; if (L <= mid) rt1 = query_cmax(bt -> ls, lf, mid, L, R); if (R > mid) rt2 = query_cmax(bt -> rs, mid + 1, rg, L, R); return max(rt1, rt2);}int query(node* bt, int lf, int rg, int L, int R){ if (L <= lf && rg <= R) return query_cmax(bt -> rt, 1, n, l - 1, r - 1); int rt1 = 0, rt2 = 0, mid = (lf + rg) >> 1; if (L <= mid) rt1 = query(bt -> ls, lf, mid, L, R); if (R > mid) rt2 = query(bt -> rs, mid + 1, rg, L, R); return max(rt1, rt2);}int main(){ init(); n = read(), m = read(); for (Acce i = 0; i <= n + 2; ++ i) root[i] = newnode(), root[i] -> rt = null; for (Acce i = 1; i <= n; ++ i) { a[i].v = read(); a[i].pre = last[a[i].v] + 1; last[a[i].v] = i; a[i].id = i; } for (Acce i = 1; i <= n + 2; ++ i) last[i] = n + 1; for (Acce i = n; i; -- i) { a[i].nxt = last[a[i].v] + 1; last[a[i].v] = i; } sort(a + 1, a + n + 1); for (Acce i = 1; i <= n; ++ i) { while(las < a[i].pre - 1) root[las + 1] = root[las], ++ las; insert(root[a[i].pre], root[a[i].pre - 1], 1, n + 2, a[i]); las = a[i].pre; } while(las < n + 1) root[las + 1] = root[las], ++ las; for (Acce i = 1; i <= m; ++ i) { l = read(), r = read(); l = (l + ans) % n + 1; r = (r + ans) % n + 1; if(l > r) swap(l, r); ++ l, ++ r; ans = query(root[l - 1], 1, n + 2, r + 1, n + 2); printf("%d\n", ans); }}
- [BZOJ]3489 A simple rmq problem 主席树套树
- BZOJ 3489: A simple rmq problem 树套树
- [主席树套堆 区间修改 标记永久化] BZOJ 3489 A simple rmq problem
- BZOJ 3489 A simple rmq problem
- 【31.94%】【BZOJ 3489】A simple rmq problem
- bzoj 3489: A simple rmq problem
- BZOJ 3489 A simple rmq problem
- BZOJ 3489 A simple rmq problem 可持久化树套树
- bzoj 3489 A simple rmq problem 可持久化树套树
- bzoj 3489: A simple rmq problem (KD-tree)
- 3489: A simple rmq problem
- bzoj 3489: A simple rmq problem 可持久化线段树套可持久化线段树
- 【BZOJ3489】A simple rmq problem
- BZOJ3489 A simple rmq problem
- bzoj3489: A simple rmq problem
- HYSBZ3489-A simple rmq problem
- [BZOJ3489]A simple rmq problem(KD-tree||主席树+KD-tree小结)
- 3489: A simple rmq problem K-D tree
- 20171124学习强化学习,尽快出论文,Q-learning2.1
- Struts Action实例化,从源码上分析
- warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared librar
- Eclipse 优化
- DDoS攻击
- [BZOJ]3489 A simple rmq problem 主席树套树
- table 'xxx' marked as crashed and should be repaired问题的处理
- 快速建立素数表
- 网摘 vue+express 博客项目
- VS编译的控制台程序发布问题
- PMP
- 序列化和读取文件内容
- spring cloud微服务分布式云架构
- error C2226: 语法错误 : 意外的“HFONT”类型