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. 转git取消commit

     如果不小心commit了一个不需要commit的文件,可以对其进行撤销. 先使用git log 查看 commit日志 commit 422bc088a7d6c5429f1d0760d008d8 ...

  2. ajax的四种type类型

    1.GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改.增加数据,不会影响资源的内容,即该请求不会产生副作用.无论进行多少次操 ...

  3. System.Reflection名称空间下的程序集类Assembly应用.

    利用反射中的程序集类(Assembly--抽象类)动态加载类库(.dll)或者可执行程序(.exe). 优点:①.可以消除if条件的逻辑判断.②.减少内存资源.③.有利于程序扩展. 缺点... 使用静 ...

  4. WebAPI 跨域解决方案.

    先下载支持跨域的.dll,然后using System.Web.Http.Cors. 我把webapi解决方案部署到IIS上了.测试过后可以解决跨域. 方案一(用了*号,这样有安全隐患.): 直接在w ...

  5. MySQL/MariaDB中游标的使用

    本文目录:1.游标说明2.使用游标3.游标使用示例 1.游标说明 游标,有些地方也称为光标.它的作用是在一个结果集中逐条逐条地获取记录行并操作它们. 例如: 其中select是游标所操作的结果集,游标 ...

  6. 详解k8s一个完整的监控方案(Heapster+Grafana+InfluxDB) - kubernetes

    1.浅析整个监控流程 heapster以k8s内置的cAdvisor作为数据源收集集群信息,并汇总出有价值的性能数据(Metrics):cpu.内存.网络流量等,然后将这些数据输出到外部存储,如Inf ...

  7. T410升级笔记

      T410 win7 旗舰版 32 sp1 三星  DDR3 1066 mhz core i5 M 540 2.53GHZ 双核 日立 HTS725032A9A364 320G/7200转/分 sa ...

  8. OAuth2.0学习(1-9)新浪开放平台微博认证-web应用授权(授权码方式)

    1. 引导需要授权的用户到如下地址: URL 1 https://api.weibo.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&respons ...

  9. byte在计算机中的存储方式--Double.byteValue()的输出结果思考

    先举三个栗子: 1. public static void main(String[] args) { Double d = new Double(123.56); byte b = d.byteVa ...

  10. c# 工具类(字符串和时间,文件)

    using System; using System.IO; using System.Text.RegularExpressions; using System.Windows.Browser; n ...