最近在研究平衡树,看起来这种东西又丧水又很深,感觉很难搞清楚。在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的更多相关文章

  1. 无旋转Treap简介

    无旋转Treap是一个神奇的数据结构,能够支持插入,删除,查询k大,查询某个数的排名,查询前驱后继,支持各种区间操作和持久化.基于旋转的Treap无法实现区间反转等操作,但是无旋Treap可以轻易地支 ...

  2. BZOJ3223文艺平衡树——非旋转treap

    此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...

  3. BZOJ3224普通平衡树——非旋转treap

    题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...

  4. Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 https://www.luogu.org/problemnew/show/P3 ...

  5. [BZOJ3223]文艺平衡树 无旋Treap

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个 ...

  6. BZOJ3678 wangxz与OJ (平衡树 无旋treap)

    题面 维护一个序列,支持以下操作: 1.在某个位置插入一段值连续的数. 2.删除在当前序列位置连续的一段数. 3.查询某个位置的数是多少. 题解 显然平衡树,一个点维护一段值连续的数,如果插入或者删除 ...

  7. 4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap

    国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区 ...

  8. Treap + 无旋转Treap 学习笔记

    普通的Treap模板 今天自己实现成功 /* * @Author: chenkexing * @Date: 2019-08-02 20:30:39 * @Last Modified by: chenk ...

  9. BZOJ3223: Tyvj 1729 文艺平衡树 无旋Treap

    一开始光知道pushdown却忘了pushup......... #include<cstdio> #include<iostream> #include<cstring ...

随机推荐

  1. Webview之H5页面调用android的图库及文件管理

    h5页面打开图片管理器 一般页面在pc打开文件管理器是用 type="file"的代码,可是这在android的webview是无效的,必须为webview设定WebChromeC ...

  2. Log4j详细教程

    一.入门实例 1.新建一个JAva工程,导入包log4j-1.2.17.jar,整个工程最终目录如下 2.src同级创建并设置log4j.properties ### 设置### log4j.root ...

  3. Hibernate之HQL

    SQL语句的DML操作不外乎:增,删,改,查 增加 :  save(),persist() 删除 :   delete() 改动 :   update() 查询  :  get() ,load() 其 ...

  4. Junit 4 测试中使用定时任务操作

    难度:测试中执行线程操作 package com.hfepc.job.dataCollection.test; import java.util.Date; import java.util.List ...

  5. EasyUI 修改 Messager 消息框大小

    需求是要修改确认消息窗口的大小. 简单的调用方法是这样的: $.messager.confirm('操作确认', '确定批量编辑文章?', function (r) { ... } 这个时候生成的弹窗 ...

  6. 启动eclipse时出现“Failed to load the JNI shared library jvm.dll”错误及解决

    昨晚安装另一个版本的eclipse,启动时出现了"Failed to load the JNI shared library jvm.dll"错误: 1.刚开始以为是因为当时没有将 ...

  7. JAVA工程师面试题【来自并发编程网】

    基础题: Java线程的状态 进程和线程的区别,进程间如何通讯,线程间如何通讯 HashMap的数据结构是什么?如何实现的.和HashTable,ConcurrentHashMap的区别 Cookie ...

  8. python实现归并排序,归并排序的详细分析。

    学习归并排序的过程是十分痛苦的.它并不常用,看起来时间复杂度好像是几种排序中最低的,比快排的时间复杂度还要低,但是它的执行速度不是最快的.很多朋友不理解时间复杂度低为什么运行速度不一定快,这个不清楚的 ...

  9. c语言一个显示星号的函数(隐藏密码)

    显示星号 void star(char p[])    //显示星号 {     int j; while((p[j] = getch())!='\r') { if(p[j] !='\b') { pr ...

  10. Downloader Middleware

    downloader middleware作用:改写请求,如加入代理,加入头部等:处理异常等. # downloadMiddleware举例, 加代理 # 这里的类如果已经重新设置名称,记得在sett ...