今天一天怼了平衡树。深深地被她的魅力折服了。我算是领略到了高级数据结构的美妙。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,且最小的数)

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. using namespace std;
  6. #define pos(i,a,b) for(int i=(a);i<=(b);i++)
  7. #define pos2(i,a,b) for(int i=(a);i>=(b);i--)
  8. #define N 500010
  9. struct Treap
  10. {
  11. int l,r,w,v,size,rnd;
  12. //v为实际数值;rnd为优先级;size为以它为根的子树大小;w为自身节点存的数的个数(数据可以有多个重复的数)
  13. }tree[N];
  14. int n;
  15. int root,size;
  16. void update(int k)
  17. {
  18. tree[k].size=tree[tree[k].l].size+tree[tree[k].r].size+tree[k].w;
  19. //更新子树大小
  20. }
  21. void rturn(int &k)
  22. {
  23. int t=tree[k].l;
  24. tree[k].l=tree[t].r;
  25. tree[t].r=k;
  26. tree[t].size=tree[k].size;
  27. update(k);
  28. k=t;
  29. }//右旋转
  30. void lturn(int &k)
  31. {
  32. int t=tree[k].r;
  33. tree[k].r=tree[t].l;
  34. tree[t].l=k;
  35. tree[t].size=tree[k].size;
  36. update(k);
  37. k=t;
  38. }//左旋转
  39. void insert(int &k,int x)
  40. {
  41. if(k==0)
  42. {
  43. size++;
  44. k=size;
  45. tree[k].w=tree[k].size=1;
  46. tree[k].v=x;
  47. tree[k].rnd=rand();//随机数
  48. return;
  49. }
  50. tree[k].size++;
  51. if(tree[k].v==x)//如果有多个,w++
  52. tree[k].w++;
  53. else
  54. {
  55. if(tree[k].v<x)//满足二叉排序树性质
  56. {
  57. insert(tree[k].r,x);
  58. if(tree[tree[k].r].rnd<tree[k].rnd)
  59. lturn(k);//维护堆性质,左旋转
  60. }
  61. else
  62. {
  63. insert(tree[k].l,x);
  64. if(tree[tree[k].l].rnd<tree[k].rnd)
  65. rturn(k);
  66. }
  67. }
  68. }
  69. int tmp;
  70. void query_pro(int k,int x)
  71. {
  72. if(k==0)
  73. return;
  74. if(x>tree[k].v)
  75. {
  76. tmp=k;//不断更新过程。数值小于目标值,去右子树里找 ,找到第一个比它大的值。此时更新结果即为比它小的最大的值
  77. query_pro(tree[k].r,x);
  78. }
  79. else
  80. query_pro(tree[k].l,x);
  81. }
  82. void query_sub(int k,int x)
  83. {
  84. if(k==0)
  85. return;
  86. if(x<tree[k].v)//与上面同理
  87. {
  88. tmp=k;
  89. query_sub(tree[k].l,x);
  90. }
  91. else
  92. query_sub(tree[k].r,x);
  93. }
  94. void del(int &k,int x)
  95. {
  96. if(k==0)
  97. return;
  98. if(tree[k].v==x)
  99. {
  100. if(tree[k].w>1)//若不止相同值的个数有多个,删去一个
  101. {
  102. tree[k].w--;
  103. tree[k].size--;
  104. return;
  105. }
  106. if(tree[k].l*tree[k].r==0)//有一个儿子为空
  107. k=tree[k].l+tree[k].r;
  108. else
  109. {
  110. if(tree[tree[k].l].rnd<tree[k].rnd)
  111. {
  112. rturn(k);
  113. del(k,x);
  114. }
  115. else
  116. {
  117. lturn(k);
  118. del(k,x);
  119. }
  120. }
  121. }
  122. else
  123. {
  124. if(x>tree[k].v)
  125. {
  126. tree[k].size--;
  127. del(tree[k].r,x);
  128. }
  129. else
  130. {
  131. tree[k].size--;
  132. del(tree[k].l,x);
  133. }
  134. }
  135. }
  136. int query_rank(int k,int x)
  137. {
  138. if(k==0)
  139. return 0;
  140. if(tree[k].v==x)
  141. return tree[tree[k].l].size+1;//找到目标值,左子树都比它小,左子树大小+1即为它的排名
  142. else
  143. {
  144. if(x>tree[k].v)
  145. return tree[tree[k].l].size+tree[k].w+query_rank(tree[k].r,x);
  146. else
  147. return query_rank(tree[k].l,x);
  148. }
  149. }
  150. int query_num(int k,int x)
  151. {
  152. if(k==0)
  153. return 0;
  154. if(x<=tree[tree[k].l].size)
  155. return query_num(tree[k].l,x);
  156. else
  157. if(x>tree[tree[k].l].size+tree[k].w)
  158. return query_num(tree[k].r,x-tree[tree[k].l].size-tree[k].w);
  159. else
  160. return tree[k].v;
  161. }
  162. int main()
  163. {
  164. freopen("phs.in","r",stdin);
  165. freopen("phs.out","w",stdout);
  166. scanf("%d",&n);
  167. int opt,x;
  168. pos(i,1,n)
  169. {
  170. scanf("%d%d",&opt,&x);
  171. switch(opt)
  172. {
  173. case 1:insert(root,x);break;
  174. case 2:del(root,x);break;
  175. case 3:printf("%d\n",query_rank(root,x));break;
  176. case 4:printf("%d\n",query_num(root,x));break;
  177. case 5:tmp=0;query_pro(root,x);printf("%d\n",tree[tmp].v);break;
  178. case 6:tmp=0;query_sub(root,x);printf("%d\n",tree[tmp].v);break;
  179. }
  180. }
  181. //while(1);
  182. return 0;
  183. }

  

Treap详解的更多相关文章

  1. 【数据结构】FHQ Treap详解

    FHQ Treap是什么? FHQ Treap,又名无旋Treap,是一种不需要旋转的平衡树,是范浩强基于Treap发明的.FHQ Treap具有代码短,易理解,速度快的优点.(当然跟红黑树比一下就是 ...

  2. FHQ Treap 详解

    鲜花 一些鲜花放在前面,平衡树学了很久,但是每学一遍都忘,原因就在于我只能 70% 理解 + 30% 背板子,所以每次都忘.这次我采取了截然不同的策略,自己按照自己的理解打一遍,大获成功(?),大概打 ...

  3. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  4. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  5. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  6. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  7. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

  8. Android Notification 详解——基本操作

    Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...

  9. Git初探--笔记整理和Git命令详解

    几个重要的概念 首先先明确几个概念: WorkPlace : 工作区 Index: 暂存区 Repository: 本地仓库/版本库 Remote: 远程仓库 当在Remote(如Github)上面c ...

随机推荐

  1. Python的迭代器与生成器

    Python中的生成器和迭代器方便好用,但是平时对生成器和迭代器的特性掌握的不是很到位,今天将这方面的知识整理一下. 迭代器 为了更好的理解迭代器和生成,我们需要简单的回顾一下迭代器协议的概念. 迭代 ...

  2. 执行3小时超长SQL的分析优化过程:从索引遇见IS NULL,到最佳实践

    月底高峰期,对一个典型项目抽查分析时,发现了一个超级慢.全表扫描的SQL,语句很简单,AWR中赫然在列,在我统计的截止时间内还没有结束... 使用v$active_session_history进一步 ...

  3. 错误代码是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 是无法给远程连接的用 ...

  4. VB6之ICMP实现ping功能

    代码备忘 'code by lichmama from cnblogs.com Private Type IPAddr ip1 As Byte ip2 As Byte ip3 As Byte ip4 ...

  5. Unity3D-Shader-人物残影效果

    [旧博客转移 - 2016年1月7日 00:24 ] 前面的话 上一篇讲了一下人物边缘发光效果,链接: Unity-ShaderLab-实现X光效果,这次我们利用这个Shader来实现人物残影效果 先 ...

  6. 基于Bootstrap+angular的一个豆瓣电影app

    1.搭建项目框架 npm初始化项目 npm init -y //按默认配置初始化项目 安装需要的第三方库 npm install bootstrap angular angular-route --s ...

  7. Oracle,Mysql ,SQL Server 三大数据库带参数的模糊查询, 拼接查询条件问题

    最近项目开发一直在不断切换数据库,有时候一条sql 要同时考虑多种数据库中的兼容问题 , 先总结一条模糊查询拼接查询条件的问题,后续追加总结. 目前使用   mybatis: 1. Oracle 中使 ...

  8. Unrooted Tests错误

    使用Junit4做测试,遇到如下问题: 条件如下: Eclipse里的Maven工程. 使用JUnit4(这个是否必须不知,反正我的工程用的4) 修改某个Test类里的方法名,或者增加一个Test方法 ...

  9. JavaScript一个鼠标滚动事件的实例

    <script type="text/javascript" src="./whenReady.js"></script> <!- ...

  10. [CF373C]计算袋鼠是愉快的(Counting Kangaroos is Fun)-贪心

    Problem 计算袋鼠是愉快的 题目大意 有n只袋鼠,如果一个袋鼠体积是另一个袋鼠的两倍或以上,则小袋鼠能被大袋鼠装进袋子里,装进去后就看不到袋子里的袋鼠了,问这群袋鼠如何行动才能使得它们看着数量最 ...