题目背景

本题为题目 普通平衡树 的可持久化加强版。

数据已经经过强化

感谢@Kelin 提供的一组hack数据

题目描述

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

  1. 插入x数

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

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

  4. 查询排名为x的数

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

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

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

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

输入输出格式

输入格式:

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

接下来每行包含三个整数,第 i 行记为 vi​,opti​,xi​。

vi​表示基于的过去版本号( 0≤vi​<i ),opti​ 表示操作的序号( 1≤opt≤6 ), xi​ 表示参与操作的数值

输出格式:

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

输入输出样例

输入样例#1:

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
输出样例#1:

9
1
2
10
3

说明

数据范围:

对于28%的数据满足: 1≤n≤10

对于44%的数据满足: 1≤n≤2⋅10^2

对于60%的数据满足: 1≤n≤3⋅10^3

对于84%的数据满足: 1≤n≤10^5

对于92%的数据满足: 1≤n≤2⋅10^5

对于100%的数据满足: 1≤n≤5⋅10^5 , −10^9≤xi​≤10^9

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

样例说明:

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

  1. [][]

  2. [9][9]

  3. [3, 9][3,9]

  4. [9, 10][9,10]

  5. [3, 9][3,9]

  6. [9, 10][9,10]

  7. [2, 9, 10][2,9,10]

  8. [2, 9, 10][2,9,10]

  9. [2, 10][2,10]

  10. [2, 10][2,10]

  11. [3, 9][3,9]

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long read()
{
long long x=,f=;
char ch=getchar();
while(ch>''||ch<'')
{
if(ch=='-')
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
const int maxn=5e5+;
struct node
{
int l,r,v,rd,sum;
} e[maxn*];
int n,num,x,y,opt;
int root[maxn];
void update(int i)
{
if(!i)
return ;
e[i].sum=e[e[i].l].sum+e[e[i].r].sum+;
}
int add(int x)
{
++num;
e[num].l=e[num].r=;
e[num].sum=;
e[num].v=x;
e[num].rd=rand();
return num;
}
int merge(int x,int y)
{
if(!x||!y)
return x+y;
if(e[x].rd>e[y].rd)
{
int p=++num;
e[p]=e[x];
e[p].r=merge(e[p].r,y);
update(p);
return p;
}
else
{
int p=++num;
e[p]=e[y];
e[p].l=merge(x,e[p].l);
update(p);
return p;
}
}
void split(int now,int k,int &x,int &y)
{
if(now==)
{
x=y=;
return ;
}
if(e[now].v<=k)
{
x=++num;
e[x]=e[now];
split(e[x].r,k,e[x].r,y);
update(x);
}
else
{
y=++num;
e[y]=e[now];
split(e[y].l,k,x,e[y].l);
update(y);
}
}
void insert(int &root,int v)
{
int x=,y=,z=;
split(root,v-,x,y);
z=add(v);
root=merge(merge(x,z),y);
}
void del(int &root,int v)
{
int x=,y=,z=;
split(root,v,x,z);
split(x,v-,x,y);
y=merge(e[y].l,e[y].r);
root=merge(merge(x,y),z);
}
int rank(int i,int k)
{
if(k==e[e[i].l].sum+)
return e[i].v;
if(k<=e[e[i].l].sum)
return rank(e[i].l,k);
return rank(e[i].r,k-e[e[i].l].sum-);
}
int query(int &root,int v)
{
int x,y;
split(root,v-,x,y);
int ans=e[x].sum+;
root=merge(x,y);
return ans;
}
int pre(int &root,int v)
{
int x,y,k;
split(root,v-,x,y);
if(x==)
return -;
k=e[x].sum;
int ans=rank(x,k);
root=merge(x,y);
return ans;
}
int nex(int &root,int v)
{
int x,y,ans;
split(root,v,x,y);
if(y==)
return ;
ans=rank(y,);
root=merge(x,y);
return ans;
}
int main()
{
n=read();
for(int i=; i<=n; i++)
{
x=read(),opt=read(),y=read();
root[i]=root[x];
if(opt==)
insert(root[i],y);
if(opt==)
del(root[i],y);
if(opt==)
printf("%d\n",query(root[i],y));
if(opt==)
printf("%d\n",rank(root[i],y));
if(opt==)
printf("%d\n",pre(root[i],y));
if(opt==)
printf("%d\n",nex(root[i],y));
}
return ;
}

洛谷P3835 【模板】可持久化平衡树的更多相关文章

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

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

  2. 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]

    题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...

  3. 洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)

    题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#def ...

  4. 洛谷 P3835: 【模板】可持久化平衡树

    题目传送门:洛谷P3835. 题意简述: 题面说的很清楚了. 题解: 考虑建立一棵每个节点都表示一个版本的树. 以初始版本 \(0\) 为根.对于第 \(i\) 个操作,从 \(v_i\) 向 \(i ...

  5. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  6. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  7. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

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

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

  9. 【AC自动机】洛谷三道模板题

    [题目链接] https://www.luogu.org/problem/P3808 [题意] 给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过. [题解] 不再介绍基础知识了,就是裸的模 ...

随机推荐

  1. js中escape对应的C#解码函数 UrlDecode

    js中escape对应的C#解码函数 System.Web.HttpUtility.UrlDecode(s),使用过程中有以下几点需要注意   js中escape对应的C#解码函数 System.We ...

  2. windows 下 bat 计划任务删除保留时间内文件

    date  windows 打印时间戳  年:echo %date:~,% 月:echo %date:~,% 日:echo %date:~,% 星期:echo %date:~,% 小时:echo %t ...

  3. 关于MySQL中的8个 character_set 变量

    https://blog.csdn.net/sun8112133/article/details/79921734 本篇会简单介绍在 MySQL 中关于 8个 character_set 变量的基本作 ...

  4. Redis 如何实现持久化

    1.RDB 持久化,将 Redis 在内存中的的状态保存到硬盘中,相当于备份数据库状态. 2.AOF 持久化(Append-Only-File),AOF 持久化是通过保存 Redis 服务器锁执行的写 ...

  5. mysql 迁移

    背景 这次做oracle数据迁移,也想总结像mysql的数据迁移方式.简单列下吧,因为具体方式网上很多. 方式 可以通过修改mysql.ini的数据文件目录位置方法实现拷贝迁移,此种方式简单 通过备份 ...

  6. 5、Filebeat工作原理

    Filebeat工作原理 Filebeat由两个主要组件组成:inputs和harvesters. 这些组件协同工作来查看最新文件内容并将事件数据发送到指定的输出.(注意与之前版本的不同,之前版本是p ...

  7. javascript 路径读取

    //获取当前文件全路径 <script language="javascript"> alert(window.location.href); alert(window ...

  8. CTeX入门出坑

    终于出了入门坑.大致风格可以了.赶紧记下来. \documentclass{ctexbook} \usepackage{amsmath} \usepackage{amsfonts} \usepacka ...

  9. 下面为初学者分享一下SQL 数据库学习资料

    一.基础 1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备份 ...

  10. loadrunner之java user脚本开发

    脚本开发环境: loadrunner11.0 jdk1.6.32_x86_32 脚本开发 1.选择JavaVuser协议 2.配置java环境(Vuser--RunTime Settings) 3.开 ...