题目背景

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

数据已经经过强化

感谢@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实现把网页table导成Excel(bootstrap、JqGrid、Json)

    方案一:支持IE //导出excel function exportExcel(DivID,strTitle){ if(DivID==null) { return false; } var jXls, ...

  2. Ubuntu解决没有可安装候选软件包

    解决方法:可以使用apt-cache search <package_name>寻找. 例如: E: 软件包 libqglviewer-dev 没有可安装候选 解决方法: apt-cach ...

  3. LeetCode第十一题-可以装最多水的容器

    Container With Most Water 问题简介:通过一个给定数组,找出最大的矩形面积 问题详解:给定一个数组,包含n个非负整数a1,a2,…,an,其中每个表示坐标(i,ai)处的点,绘 ...

  4. NYOJ

    爬行的蚂蚁 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 有N只蚂蚁以每秒1cm的速度在长为Lcm的竿子上爬行.当蚂蚁爬到竿子的端点时就会掉落.由于竿子太细,两只蚂 ...

  5. uni-app调用原生的文件系统管理器(可选取附件上传)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  6. 浅析Memcache和Redis

    想必开发的小伙伴们对Memcache和Redis都不陌生吧,最近正好在整理它们,于是就写一下博客吧!一方面是分享,另一方面便于自己查找. 首先,来说说Memcache和Redis是什么? 说得简单一点 ...

  7. 怎么给PDF文件交换页面

    在使用PDF文件的时候有文件页面的排版错误的时候,这个时候就需要交换页面了,那么怎么给PDF文件交换页面呢,在使用PDF文件的时候需要交换页面的时候要怎么做呢,下面小编就为大家分享一下PDF文件交换页 ...

  8. 使用CompletionService结合ExecutorService批处理调用存储过程任务实例

    此实例为java多线程并发调用存储过程实例,只做代码记载,不做详细描述 1.线程池构造初始化类CommonExecutorService.java package com.pupeiyuan.go; ...

  9. Actor消息发送及等待结果关键字

    class Task extends Actor{ override def act(): Unit = { while(true){ receive({ case SmTask(file) => ...

  10. Spring Boot mybatis HashMap +layui 通用分页

    背景: mybatis 常用数据查询的方法都是先建实体类,再建Mapper,最后写Service,如果只是单纯的去查询数据显示,这样操作太麻烦.本文就以mybatis +layui创建通用分页类,简化 ...