【数据结构】【平衡树】无旋转treap
最近在研究平衡树,看起来这种东西又丧水又很深,感觉很难搞清楚。在Ditoly学长的建议下,我先学习了正常的treap,个人感觉这应该是平衡树当中比较好懂的而且比较好写的一种。
然而,发现带旋treap有很多无法支持的操作,例如各种区间操作,而且由于会旋转无法可持久化,这是一个十分影响实用性的问题,在没有办法支持区间操作的情况下,我有2种选择:
1)滚去学splay;2)学习无旋treap 正常人应该都会去学习splay,然而我选择了后者,因为貌似splay在FJ省选R2T1中被卡成傻逼了。。。。有个学长因此此题爆0。。。心疼。。。。。
所以准备先搞一搞无旋treap,再去搞splay。
**********************华丽的分割线***************************************************
以下是正文。
无旋treap,顾名思义就是没有了rotate的treap,而我们在无旋treap中十分重要的就是2个基础操作,可以说这2个操作才给我们带来了使用无旋treap的理由,它们就是merge(合并treap)和split(分离treap)。
你Insert要用到它们,Delete要用到它们,查询还是需要它们。。。。
这里首先强调一点,merge中合并的2棵treap是要求相对有序的,换而言之就是其中一棵treap的最右节点要严格不大于另一棵的最左节点,不然就和永无乡那题一样,你得写启发式合并暴力merge了,有兴趣的可以看一下那一篇的题解,然而和本题没有并没有毛线关系23333。
然后先看一道例题吧。。。这题在之前我写了一个标准的普通版treap,题解戳这里,不了解普通treap的和没看过原题的可以先看这一篇(当然还是建议在彻底理解的前提下阅读本文,而且本人语文感人,表达能力可能不佳,见谅,如果想要深入学习,建议看dalao的这篇)。
首先这是一道平衡树模板题,因为没有区间操作,所以你写普通treap是能过的。
接下来带有区间操作的模板题我另开一篇写了一道模板题,传送门戳我。
然后讲一下基本操作的实现:(不懂的可以最后结合本人代码理解:D)
I.merge(A,B)
A和B是2棵treap,实际上我们操作上是2个root。
首先我们默认max(A)是小于min(B)的。
然后当前的2棵treap的root节点,我们判断一下优先级,然后默认小的扔上面(维护treap性质),例如:
若A.pri<B.pri(即合并后A为B的祖先),我们显然A的左子树不需更改,而我们需要更改A的是右子树,因此令A的右儿子为merge(A.rightson,B)的root即可。
反之同理即上述内容的反演。
II.split(A,k)
split操作是分离A这棵treap中前K大的和后面的。
显然你只需要按照rank跑一遍找到分界点,然后根据每次是向左跑还是向右跑决定这个点属于哪一棵分出来的树:
1)向左跑说明这个点的权值较大,它以及它的右子树均属于第二棵treap;2)向右跑说明这个点及其左子树均被在前K个,属于第一棵treap。
因为这样的treap,没有了旋转操作,因此是可持久化的,这里改日再讲。
接下来回归模板题的基本操作。首先先默认权值相等的我们扔到右子树。
I)Insert 插入一个权值为val的节点。
我们只需要查找这个点在treap中的rank(记为k),然后split之后增加这个节点进行merge即可。
II)Delete 删去一个权值为val的节点。
我们只需要查找这个节点在treap中的rank,然后split分离出这个节点,然后对于剩下的2棵treap进行merge即可。
III)getkth 查找权值val在树上的最小排名。
由于我们正常查找返回的是最后的位置,所以查找(val-1)在树上的rank再+1即可。
IV)findkth 查找树上排名为rank的权值。
直接split分离这个点然后记录权值后再merge回去。
V)prefix 查找树上权值小于val的最大值。
直接findkth(getkth(val-1))即可。
VI)suffix查找树上权值大于val的最小值。
直接findkth(getkth(val)+1)即可。
接下来给出代码帮助大家理解,当然是跑得没有普通treap快的就是了。
#include <stdio.h>
#include <algorithm>
#define r register
#define getchar() (S==TT&&(TT=(S=BB)+fread(BB,1,1<<15,stdin),TT==S)?EOF:*S++)
char BB[<<],*S=BB,*TT=BB;
inline int in(){
r int x=;r bool f=;r char c;
for (;(c=getchar())<''||c>'';) f=c=='-';
for (x=c-'';(c=getchar())>=''&&c<='';) x=(x<<)+(x<<)+c-'';
return f?-x:x;
}
namespace Treap{
inline int Rand(){
static int x=;
return x^=x<<,x^=x>>,x^=x<<;
}
struct node{
node *ls,*rs;
int val,pri,sz;
node(int val):val(val),pri(Rand()),ls(NULL),rs(NULL),sz(){};
inline void combine(){sz=+(ls?ls->sz:)+(rs?rs->sz:);}
}*root;
inline int Size(node *x){return x?x->sz:;}
node *merge(node *a,node *b){
if (!a) return b;if (!b) return a;
if (a->pri<b->pri){
a->rs=merge(a->rs,b);
a->combine();
return a;
}else{
b->ls=merge(a,b->ls);
b->combine();
return b;
}
}
typedef std::pair<node*,node*> Droot;
Droot split(node *x,int k){
if (!x) return Droot(NULL,NULL);
r Droot y;
if (Size(x->ls)>=k){
y=split(x->ls,k);
x->ls=y.second;
x->combine();
y.second=x;
}else{
y=split(x->rs,k-Size(x->ls)-);
x->rs=y.first;
x->combine();
y.first=x;
}return y;
}
inline int findkth(int k){
r Droot x=split(root,k-);
r Droot y=split(x.second,);
r node *ans=y.first;
root=merge(merge(x.first,ans),y.second);
return ans->val;
}
int getkth(node *x,int val){
if (!x) return ;
return val<x->val?getkth(x->ls,val):getkth(x->rs,val)+Size(x->ls)+;
}
inline void Insert(int val){
r int k=getkth(root,val);
r Droot x=split(root,k);
r node *a=new node(val);
root=merge(merge(x.first,a),x.second);
}
inline void Delete(int val){
r int k=getkth(root,val);
r Droot x=split(root,k-);
r Droot y=split(x.second,);
r node *ans=y.first;
root=merge(x.first,y.second);
delete ans; ans=NULL;
}
inline int prefix(int val){
r int k=getkth(root,val-);
return findkth(k);
}
inline int suffix(int val){
r int k=getkth(root,val);
return findkth(k+);
}
}
void work(){
int q=in();
while(q--){
r int op=in(),x=in();
switch(op){
case :Treap::Insert(x);break;
case :Treap::Delete(x);break;
case :printf("%d\n",Treap::getkth(Treap::root,x-)+);break;
case :printf("%d\n",Treap::findkth(x));break;
case :printf("%d\n",Treap::prefix(x));break;
case :printf("%d\n",Treap::suffix(x));break;
}
}
}
int main(){work();return ;}
【数据结构】【平衡树】无旋转treap的更多相关文章
- 无旋转Treap简介
无旋转Treap是一个神奇的数据结构,能够支持插入,删除,查询k大,查询某个数的排名,查询前驱后继,支持各种区间操作和持久化.基于旋转的Treap无法实现区间反转等操作,但是无旋Treap可以轻易地支 ...
- BZOJ3223文艺平衡树——非旋转treap
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...
- BZOJ3224普通平衡树——非旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
- Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 https://www.luogu.org/problemnew/show/P3 ...
- [BZOJ3223]文艺平衡树 无旋Treap
3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个 ...
- BZOJ3678 wangxz与OJ (平衡树 无旋treap)
题面 维护一个序列,支持以下操作: 1.在某个位置插入一段值连续的数. 2.删除在当前序列位置连续的一段数. 3.查询某个位置的数是多少. 题解 显然平衡树,一个点维护一段值连续的数,如果插入或者删除 ...
- 4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap
国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区 ...
- Treap + 无旋转Treap 学习笔记
普通的Treap模板 今天自己实现成功 /* * @Author: chenkexing * @Date: 2019-08-02 20:30:39 * @Last Modified by: chenk ...
- BZOJ3223: Tyvj 1729 文艺平衡树 无旋Treap
一开始光知道pushdown却忘了pushup......... #include<cstdio> #include<iostream> #include<cstring ...
随机推荐
- Beta冲刺链接总汇
Beta冲刺 咸鱼 Beta 冲刺day1 Beta 冲刺day2 Beta 冲刺day3 Beta 冲刺day4 Beta 冲刺day5 Beta 冲刺day6 Beta 冲刺day7 凡事预则立- ...
- js计时功能
//个位秒加 function time4jia() { //分钟60为上限 所有加停止 if (sz(a('time1').innerHTML) == 6) { return; } var m4 = ...
- 静态关键字static用法。
static的特点:1,static是一个修饰符,用于修饰成员.2,static修饰的成员被所有的对象所共享.3,static优先于对象存在,因为static的成员随着类的加载就已经存在了. 4,st ...
- sqlserver之排序规则和ETL不支持sqlserverdatetime2的问题
sqlserver的排序规则大概分为Windows 排序规则和 SQL Server 排序规则.数据在安装的时候,默认不设置会默认为SQL_Latin1_General_CP1_CI_AI.数据库在创 ...
- 构建微服务开发环境3————Java应用的优秀管理工具Maven的下载安装及配置
[内容指引] 下载安装包: MacOS下Maven的安装及配置: Windows下Maven的安装及配置. 一.下载安装包 进入Maven的官方下载地址:http://maven.apache.org ...
- PostgreSQL 客户端乱码问题
关于客户端和服务器端的乱码问题, POSTGRESQL字符集问题总结 总结的很详细, 特别棒. 这里让我头痛了很久的问题在于 终端 上字符编码的问题, 由于我的mbp上的 iterm2 的默认编码为 ...
- OO第一次总结
第一次作业: 第一次作业的指导书发下来之后我按着上面的步骤一步一步的做了之后发现项目拉下来了,怎么开始码代码呢...然后在舍友的帮助下才知道怎么建包建类,然后对Java的语法又不是很了解,于是就先把C ...
- JAVA_SE基础——52.匿名内部类
电信的电箱烧了,害我断了2天网,真拿命,耽误了 Java匿名内部类的总结: 没有名字的内部类.就是内部类的简化形式.一般只用一次就可以用这种形式.匿名内部类其实就是一个匿名子类对象.想要定义匿名内部类 ...
- django处理cookie的机制
title: django处理cookie的机制 tags: djaogo, cookie, session grammar_cjkRuby: true --- cookie的意义 在多数日常使用的网 ...
- MySQL 避免重复数据的批量插入与批量更新
[转发] 导读 我们在向数据库里批量插入数据的时候,会遇到要将原有主键或者unique索引所在记录更新的情况,而如果没有主键或者unique索引冲突的时候,直接执行插入操作. 这种情况下,有三种方式执 ...