【数据结构】【平衡树】无旋转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 ...
随机推荐
- 简易web服务器
当通过Socket开发网络应用程序的时候,首先需要考虑所使用的网络类型,主要包括以下三个方面: 1)Socket类型,使用网络协议的类别,如IPv4的类型为PF_INET. 2)数据通信的类型,常见的 ...
- Beta阶段敏捷冲刺报告-DAY2
Beta阶段敏捷冲刺报告-DAY2 Scrum Meeting 敏捷开发日期 2017.11.3 会议时间 13:00 会议地点 微信群 参会人员 项目组全体成员 会议内容 打包问题修复, 爬虫优化, ...
- Beat冲刺报告---Day0
Beta阶段报告---Day0 1.需要改进完善的功能 我们上一阶段开发由于开发时间匆忙,对于爬虫耗时的优化没有考虑.优化的空间我在Alpha阶段的总结报告里说过,具体看下图. 这张图显示出爱 ...
- Flask 学习 十五 性能
记录影响性能的数据库查询 app/main/views.py from flask_sqlalchemy import get_debug_queries @main.after_app_reques ...
- navicate连接不上阿里云mysql
一 用xshell连接进入服务器: 二 使用命令连接mysql mysql -uroot -p 三 更新权限 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDE ...
- 点击一次按钮,发生多次ajax请求
项目中遇到了两种情况: 1.点击一次发生两次请求. 原因:submit类型的按钮,默认有提交行为,发生两次提交的原因是在执行完ajax请求后,并没有阻止submit的行为,所以解决方法有两种: a.不 ...
- 微信小程序如何动态增删class类名
简述 由于微信小程序开发不同于以往的普通web开发, 因此无法通过js获取wxml文件的dom结构, 因此从js上直接添加一个类名应该不可能了. 可是我们可以通过微信小程序数据绑定以及view标签的& ...
- 为什么java中用枚举实现单例模式会更好
代码简洁 这是迄今为止最大的优点,如果你曾经在Java5之前写过单例模式代码,那么你会知道即使是使用双检锁你有时候也会返回不止一个实例对象.虽然这种问题通过改善java内存模型和使用volatile变 ...
- js判断语句关于true和false后面跟数字或字符串的问题
我经常在代码中看到很长串判断,看到就头疼,简单的整理一下. 比如:(client.top>=0&&client.left>=0&&client.bottom ...
- wordpress怎么禁止文章复制
登陆你的网站后台--点击菜单栏的"外观"--点击"编辑"--在右侧,找到footer.php,打开它--在</body>之前加入以下代码: 1.禁止 ...