Treap详解
今天一天怼了平衡树。深深地被她的魅力折服了。我算是领略到了高级数据结构的美妙。oi太神奇了。
今天初识平衡树,选择了Treap。
Treap又叫树堆,是一个二叉搜索树。我们知道,它的节点插入是随机的,这样大多数情况下一个平衡的树。但是存在极其特殊的情况,就是树退化成链,这样无法支持我们期望的O(log)效率了。所以我们需要给树附加一个随机的域(里面可以理解为优先级),使树构成二叉排序树的同时,还要满足堆的性质。
Treap树建立具体解释:
我们可以使节点优先级大于儿子节点。可以让节点随机域的数值是以它为根的子树里面最小的,左右儿子都比它大,这样是不是就满足堆的性质了?hhh
至于我们要求的本身的数值,要满足二叉排序树的性质,左子树都比它小,右子树都比它大。
下面我来介绍Treap的具体操作和代码
最重要的是旋转操作,其他操作我会在代码中解释。
因为要维护堆的性质,所以要旋转。
因为要维护堆的性质,要把x旋转到node的位置。这时要满足二叉排序树的性质。Node>P>X.旋转后我们依然要满足这个性质。所以我们要让P为node的左儿子,node为X的右儿子。
代码详尽解释:
支持以下操作:
1.插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<cstdlib>
- using namespace std;
- #define pos(i,a,b) for(int i=(a);i<=(b);i++)
- #define pos2(i,a,b) for(int i=(a);i>=(b);i--)
- #define N 500010
- struct Treap
- {
- int l,r,w,v,size,rnd;
- //v为实际数值;rnd为优先级;size为以它为根的子树大小;w为自身节点存的数的个数(数据可以有多个重复的数)
- }tree[N];
- int n;
- int root,size;
- void update(int k)
- {
- tree[k].size=tree[tree[k].l].size+tree[tree[k].r].size+tree[k].w;
- //更新子树大小
- }
- void rturn(int &k)
- {
- int t=tree[k].l;
- tree[k].l=tree[t].r;
- tree[t].r=k;
- tree[t].size=tree[k].size;
- update(k);
- k=t;
- }//右旋转
- void lturn(int &k)
- {
- int t=tree[k].r;
- tree[k].r=tree[t].l;
- tree[t].l=k;
- tree[t].size=tree[k].size;
- update(k);
- k=t;
- }//左旋转
- void insert(int &k,int x)
- {
- if(k==0)
- {
- size++;
- k=size;
- tree[k].w=tree[k].size=1;
- tree[k].v=x;
- tree[k].rnd=rand();//随机数
- return;
- }
- tree[k].size++;
- if(tree[k].v==x)//如果有多个,w++
- tree[k].w++;
- else
- {
- if(tree[k].v<x)//满足二叉排序树性质
- {
- insert(tree[k].r,x);
- if(tree[tree[k].r].rnd<tree[k].rnd)
- lturn(k);//维护堆性质,左旋转
- }
- else
- {
- insert(tree[k].l,x);
- if(tree[tree[k].l].rnd<tree[k].rnd)
- rturn(k);
- }
- }
- }
- int tmp;
- void query_pro(int k,int x)
- {
- if(k==0)
- return;
- if(x>tree[k].v)
- {
- tmp=k;//不断更新过程。数值小于目标值,去右子树里找 ,找到第一个比它大的值。此时更新结果即为比它小的最大的值
- query_pro(tree[k].r,x);
- }
- else
- query_pro(tree[k].l,x);
- }
- void query_sub(int k,int x)
- {
- if(k==0)
- return;
- if(x<tree[k].v)//与上面同理
- {
- tmp=k;
- query_sub(tree[k].l,x);
- }
- else
- query_sub(tree[k].r,x);
- }
- void del(int &k,int x)
- {
- if(k==0)
- return;
- if(tree[k].v==x)
- {
- if(tree[k].w>1)//若不止相同值的个数有多个,删去一个
- {
- tree[k].w--;
- tree[k].size--;
- return;
- }
- if(tree[k].l*tree[k].r==0)//有一个儿子为空
- k=tree[k].l+tree[k].r;
- else
- {
- if(tree[tree[k].l].rnd<tree[k].rnd)
- {
- rturn(k);
- del(k,x);
- }
- else
- {
- lturn(k);
- del(k,x);
- }
- }
- }
- else
- {
- if(x>tree[k].v)
- {
- tree[k].size--;
- del(tree[k].r,x);
- }
- else
- {
- tree[k].size--;
- del(tree[k].l,x);
- }
- }
- }
- int query_rank(int k,int x)
- {
- if(k==0)
- return 0;
- if(tree[k].v==x)
- return tree[tree[k].l].size+1;//找到目标值,左子树都比它小,左子树大小+1即为它的排名
- else
- {
- if(x>tree[k].v)
- return tree[tree[k].l].size+tree[k].w+query_rank(tree[k].r,x);
- else
- return query_rank(tree[k].l,x);
- }
- }
- int query_num(int k,int x)
- {
- if(k==0)
- return 0;
- if(x<=tree[tree[k].l].size)
- return query_num(tree[k].l,x);
- else
- if(x>tree[tree[k].l].size+tree[k].w)
- return query_num(tree[k].r,x-tree[tree[k].l].size-tree[k].w);
- else
- return tree[k].v;
- }
- int main()
- {
- freopen("phs.in","r",stdin);
- freopen("phs.out","w",stdout);
- scanf("%d",&n);
- int opt,x;
- pos(i,1,n)
- {
- scanf("%d%d",&opt,&x);
- switch(opt)
- {
- case 1:insert(root,x);break;
- case 2:del(root,x);break;
- case 3:printf("%d\n",query_rank(root,x));break;
- case 4:printf("%d\n",query_num(root,x));break;
- case 5:tmp=0;query_pro(root,x);printf("%d\n",tree[tmp].v);break;
- case 6:tmp=0;query_sub(root,x);printf("%d\n",tree[tmp].v);break;
- }
- }
- //while(1);
- return 0;
- }
Treap详解的更多相关文章
- 【数据结构】FHQ Treap详解
FHQ Treap是什么? FHQ Treap,又名无旋Treap,是一种不需要旋转的平衡树,是范浩强基于Treap发明的.FHQ Treap具有代码短,易理解,速度快的优点.(当然跟红黑树比一下就是 ...
- FHQ Treap 详解
鲜花 一些鲜花放在前面,平衡树学了很久,但是每学一遍都忘,原因就在于我只能 70% 理解 + 30% 背板子,所以每次都忘.这次我采取了截然不同的策略,自己按照自己的理解打一遍,大获成功(?),大概打 ...
- Linq之旅:Linq入门详解(Linq to Objects)
示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解
前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...
- Java 字符串格式化详解
Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- Git初探--笔记整理和Git命令详解
几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...
随机推荐
- Python的迭代器与生成器
Python中的生成器和迭代器方便好用,但是平时对生成器和迭代器的特性掌握的不是很到位,今天将这方面的知识整理一下. 迭代器 为了更好的理解迭代器和生成,我们需要简单的回顾一下迭代器协议的概念. 迭代 ...
- 执行3小时超长SQL的分析优化过程:从索引遇见IS NULL,到最佳实践
月底高峰期,对一个典型项目抽查分析时,发现了一个超级慢.全表扫描的SQL,语句很简单,AWR中赫然在列,在我统计的截止时间内还没有结束... 使用v$active_session_history进一步 ...
- 错误代码是1130,ERROR 1130: Host xxx.xxx.xxx.xxx is not allowed to connect to this MySQL server 是无法给远程连接的用户权限问题
错误代码是1130,ERROR 1130: Host xxx.xxx.xxx.xxx is not allowed to connect to this MySQL server 是无法给远程连接的用 ...
- VB6之ICMP实现ping功能
代码备忘 'code by lichmama from cnblogs.com Private Type IPAddr ip1 As Byte ip2 As Byte ip3 As Byte ip4 ...
- Unity3D-Shader-人物残影效果
[旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...
- 基于Bootstrap+angular的一个豆瓣电影app
1.搭建项目框架 npm初始化项目 npm init -y //按默认配置初始化项目 安装需要的第三方库 npm install bootstrap angular angular-route --s ...
- Oracle,Mysql ,SQL Server 三大数据库带参数的模糊查询, 拼接查询条件问题
最近项目开发一直在不断切换数据库,有时候一条sql 要同时考虑多种数据库中的兼容问题 , 先总结一条模糊查询拼接查询条件的问题,后续追加总结. 目前使用 mybatis: 1. Oracle 中使 ...
- Unrooted Tests错误
使用Junit4做测试,遇到如下问题: 条件如下: Eclipse里的Maven工程. 使用JUnit4(这个是否必须不知,反正我的工程用的4) 修改某个Test类里的方法名,或者增加一个Test方法 ...
- JavaScript一个鼠标滚动事件的实例
<script type="text/javascript" src="./whenReady.js"></script> <!- ...
- [CF373C]计算袋鼠是愉快的(Counting Kangaroos is Fun)-贪心
Problem 计算袋鼠是愉快的 题目大意 有n只袋鼠,如果一个袋鼠体积是另一个袋鼠的两倍或以上,则小袋鼠能被大袋鼠装进袋子里,装进去后就看不到袋子里的袋鼠了,问这群袋鼠如何行动才能使得它们看着数量最 ...