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. 1.由浅入深解析 SimpleDateFormat

    一.SimpleDateFormat简介 SimpleDateFormat 是一个以国别敏感的方式格式化和分析数据的具体类. 它允许格式化 (date -> text).语法分析 (text - ...

  2. Beta冲刺随笔集合

    Beta冲刺随笔集合 项目Beta预备 Beta冲刺第一天 Beta冲刺第二天 Beta冲刺第三天 Beta冲刺第四天 Beta冲刺第五天 Beta冲刺第六天 Beta冲刺第七天 用户调查报告 Bet ...

  3. 201621123060 《Java程序设计》第五周学习总结

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 继承.多态.抽象类与接口 1.2 尝试使用思维导图将这些关键词组织起来.注:思维导图一般不需要出现过多的字. 2. 书面作业 作 ...

  4. python clock装饰器 计算函数执行时间,执行结果及传入的参数

    import time import functools def clock(func): @functools.wraps(func)#还原被装饰函数的__name__和__doc__属性 def ...

  5. WPF自学入门(十)WPF MVVM简单介绍

     前面文章中,我们已经知道,WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI. 我们不管 ...

  6. 0基础菜鸟学前端之Vue.js

    简介:0基础前端菜鸟,啃了将近半月前端VUE框架,对前端知识有了初步的了解.下面总结一下这段时间的学习心得. 文章结构 前端基础 Vue.js简介 Vue.js常用指令 Vue.js组件 Vue.js ...

  7. 关于读取Sql Server数据库时间前端处理问题

    var time = this.CreateTime; this.CreateTime = new Date(time.replace("T", " ")).F ...

  8. 数据库 MYSQL操作(一)

    数据库  MYSQL操作总结(一) 本文主要介绍一下笔者在使用数据库操作的过程中的一些总结,主要的内容包括一下几个内容: 一.mysql 使用基础(主要包括数据库的安装.基本操作等内容) 二.mysq ...

  9. Mego开发文档 - 数据注释建模

    数据注释建模 Mego框架使用一组约定来基于CLR类来构建模型.您可以指定其他配置来补充或覆盖通过约定发现的内容. 在 Mego 中所有的数据对象必须要有主键.这里需要声明与EF不同的是框架只支持数据 ...

  10. Netty事件监听和处理(下)

    上一篇 介绍了事件监听.责任链模型.socket接口和IO模型.线程模型等基本概念,以及Netty的整体结构,这篇就来说下Netty三大核心模块之一:事件监听和处理. 前面提到,Netty是一个NIO ...