Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)

  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)

  6. 求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)

和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)

每个版本的编号即为操作的序号(版本0即为初始状态,空树)

Input

第一行包含一个正整数N,表示操作的总数。

接下来每行包含三个正整数,第 $i$ 行记为 $v_i, opt_i, x_i$。

$v_i$表示基于的过去版本号( $ 0 \leq v_i < i$ ),$opt_i$ 表示操作的序号( $ 1 \leq opt \leq 6 $ ), $x_i$ 表示参与操作的数值

Output

每行包含一个正整数,依次为各个3,4,5,6操作所对应的答案

Sample Input

10
0 1 9
1 1 3
1 1 10
2 4 2
3 3 9
3 1 2
6 4 1
6 2 9
8 6 3
4 5 8

Sample Output

9
1
2
10
3

Hint

数据范围:

对于10%的数据满足: $ 1 \leq n \leq 10 $

对于30%的数据满足: $ 1 \leq n \leq 2\cdot {10}^2 $

对于50%的数据满足: $ 1 \leq n \leq 3\cdot {10}^3 $

对于80%的数据满足: $ 1 \leq n \leq {10}^5 $

对于90%的数据满足: $ 1 \leq n \leq 2\cdot {10}^5 $

对于100%的数据满足: $ 1 \leq n \leq 5\cdot {10}^5 $ , $-{10}^9 \leq x_i \leq {10}^9$

经实测,正常常数的可持久化平衡树均可通过,请各位放心

样例说明:

共10次操作,11个版本,各版本的状况依次是:

  1. $[]$

  2. $[9]$

  3. $[3, 9]$

  4. $[9, 10]$

  5. $[3, 9]$

  6. $[9, 10]$

  7. $[2, 9, 10]$

  8. $[2, 9, 10]$

  9. $[2, 10]$

  10. $[2, 10]$

  11. $[3, 9]$

题解

用 $fhq\_treap$ 来实现可持久化。

对于新建的版本,需要更新的点只有 $split$ 和 $merge$ 经过的点。

 //It is made by Awson on 2018.1.3
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define LD long double
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = 5e5;
const int M = N*;
const int INF = ~0u>>; struct fhq_Treap {
int root[N+], ch[M+][], key[M+], lev[M+], size[M+], tot;
queue<int>mem;
int newnode(int keyy) {
int o;
if (!mem.empty()) o = mem.front(), mem.pop();
else o = ++tot;
ch[o][] = ch[o][] = , key[o] = keyy, lev[o] = rand(), size[o] = ;
return o;
}
int cpynode(int r) {
int o;
if (!mem.empty()) o = mem.front(), mem.pop();
else o = ++tot;
ch[o][] = ch[r][], ch[o][] = ch[r][], key[o] = key[r], lev[o] = lev[r], size[o] = size[r];
return o;
}
void pushup(int o) {
size[o] = size[ch[o][]]+size[ch[o][]]+;
}
void split(int o, int keyy, int &x, int &y) {
if (!o) x = y = ;
else {
if (key[o] <= keyy) {
x = cpynode(o), split(ch[x][], keyy, ch[x][], y);
pushup(x);
}else {
y = cpynode(o), split(ch[y][], keyy, x, ch[y][]);
pushup(y);
}
}
}
int merge(int x, int y) {
if (!x || !y) return x+y;
if (lev[x] < lev[y]) {
int r = cpynode(x);
ch[r][] = merge(ch[r][], y);
pushup(r); return r;
}else {
int r = cpynode(y);
ch[r][] = merge(x, ch[r][]);
pushup(r); return r;
}
}
void insert(int &o, int keyy) {
int r1, r2;
split(o, keyy, r1, r2);
o = merge(merge(r1, newnode(keyy)), r2);
}
void delet(int &o, int keyy) {
int r1, r2, r3;
split(o, keyy-, r1, r2);
split(r2, keyy, r2, r3);
if (r2) mem.push(r2);
r2 = merge(ch[r2][], ch[r2][]);
o = merge(merge(r1, r2), r3);
}
int rank(int &o, int keyy) {
int r1, r2;
split(o, keyy-, r1, r2);
int ans = size[r1]+;
o = merge(r1, r2);
return ans;
}
int get_num(int o, int rank) {
if (rank == size[ch[o][]]+) return key[o];
if (size[ch[o][]] >= rank) return get_num(ch[o][], rank);
return get_num(ch[o][], rank-(size[ch[o][]]+));
}
int get_pre(int &o, int keyy) {
int r1, r2;
split(o, keyy-, r1, r2);
int r = r1;
while (ch[r][]) r = ch[r][];
int ans = key[r];
o = merge(r1, r2);
return ans;
}
int get_nex(int &o, int keyy) {
int r1, r2;
split(o, keyy, r1, r2);
int r = r2;
while (ch[r][]) r = ch[r][];
int ans = key[r];
o = merge(r1, r2);
return ans;
}
}T;
int n, v, opt, x; void work() {
srand(time());
T.insert(T.root[], -INF);
T.insert(T.root[], INF);
scanf("%d", &n);
for (int i = ; i <= n; i++) {
scanf("%d%d%d", &v, &opt, &x);
T.root[i] = T.root[v];
if (opt == ) T.insert(T.root[i], x);
else if (opt == ) T.delet(T.root[i], x);
else if (opt == ) printf("%d\n", T.rank(T.root[i], x)-);
else if (opt == ) printf("%d\n", T.get_num(T.root[i], x+));
else if (opt == ) printf("%d\n", T.get_pre(T.root[i], x));
else printf("%d\n", T.get_nex(T.root[i], x));
}
}
int main() {
work();
return ;
}

[Luogu 3835]【模板】可持久化平衡树的更多相关文章

  1. 洛谷.3835.[模板]可持久化平衡树(fhq treap)

    题目链接 对每次Merge(),Split()时产生的节点都复制一份(其实和主席树一样).时间空间复杂度都为O(qlogq).(应该更大些 因为rand()?内存真的爆炸..) 对于无修改的操作实际上 ...

  2. luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

    luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...

  3. luoguP3835 [模板]可持久化平衡树

    https://www.luogu.org/problemnew/show/P3835 因为博主精力和实力有限,学不懂 fhq treap 了,因此只介绍 leafy tree 解法 leafy tr ...

  4. 2021.07.02 P1383 高级打字机题解(可持久化平衡树)

    2021.07.02 P1383 高级打字机题解(可持久化平衡树) 分析: 从可以不断撤销并且查询不算撤销这一骚操作可以肯定这是要咱建一棵可持久化的树(我也只会建可持久化的树,当然,还有可持久化并查集 ...

  5. Luogu P3835 【模板】可持久化平衡树(fhq Treap)

    P3835 [模板]可持久化平衡树 题意 题目背景 本题为题目普通平衡树的可持久化加强版. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本 ...

  6. [luogu P3369]【模板】普通平衡树(Treap/SBT)

    [luogu P3369][模板]普通平衡树(Treap/SBT) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除x数(若有多个相同的数,因只删 ...

  7. 数组splay ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) #include <cstdio> #define Max 100005 #define Inline _ ...

  8. 替罪羊树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 闲的没事,把各种平衡树都写写 比较比较... 下面是替罪羊树 #include <cstdio> #inc ...

  9. 红黑树 ------ luogu P3369 【模板】普通平衡树(Treap/SBT)

    二次联通门 : luogu P3369 [模板]普通平衡树(Treap/SBT) 近几天闲来无事...就把各种平衡树都写了一下... 下面是红黑树(Red Black Tree) 喜闻乐见拿到了luo ...

随机推荐

  1. C#简单入门

    公司给的一个小的practice C# vs2017 Stage 1 (cmd)1. Parse the dll (reflection)2. Write all the public methods ...

  2. alpha冲刺第六天

    一.合照 二.项目燃尽图 三.项目进展 主界面首页内容呈现 我的栏目之我的问题完成 我的栏目之我的提问完成 还是插不进去,然后打算先放一放,一直在一个地方纠结那么久脑子太乱 四.明日规划 问答界面问题 ...

  3. C++ STL常用容器基本用法汇总

    1.vector 包含头文件#include<vector> 使用命名域using namespace std 定义元素类型为T的vector vector<T> vec 增: ...

  4. splinter web测试框架

    1.安装谷歌浏览器驱动(windows把驱动解压放在Python.exe同级目录即可) http://chromedriver.storage.googleapis.com/index.html 注意 ...

  5. Django 模版语法

    一.简介 模版是纯文本文件.它可以产生任何基于文本的的格式(HTML,XML,CSV等等). 模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签. {% extends "base ...

  6. 几款有用的AndroidStudio插件

    1.Android Parcelable code generator 顾名思义,这是个生成实现了Parcelable接口的代码的插件. 在你的类中,按下alt + insert键弹出插入代码的上下文 ...

  7. 【iOS】跳转到设置页面

    iOS8.0以后有效 定位服务 定位服务有很多APP都有,如果用户关闭了定位,那么,我们在APP里面可以提示用户打开定位服务.点击到设置界面设置,直接跳到定位服务设置界面.代码如下: 1 2 3 4 ...

  8. Packet for query is too large (84 > -1).

    windows下的resin配置连接mysql,常用的安全的做法是将数据库信息配置到conf目录下的resin.xml文件中. 因为resin连接mysql不是必须的,所以resin本身没有提供mys ...

  9. UWP 页面间传递参数(常见类型string、int以及自定义类型)

    这是一篇很基础的,大佬就不要看了,也不要喷,谢谢

  10. OptaPlanner - 把example运行起来(运行并浅析Cloud balancing)

    经过上面篇长篇大论的理论之后,在开始讲解Optaplanner相关基本概念及用法之前,我们先把他们提供的示例运行起来,好先让大家看看它是如何工作的.OptaPlanner的优点不仅仅是提供详细丰富的文 ...