转自

无旋版 $Treap$。

只需要两个操作即可达到 $splay$ 的所有功能

1、$split$

它的主要思想就是把一个 $Treap$ 分成两个。

$split$ 操作有两种类型,一种是按照权值分配,一种是按前 k 个分配。

第一种就是把所有小于 k 的权值的节点分到一棵树中,第二种是把前 k 个分到一个树里。

权值版:

  1. void split(int o,int k,int &x,int &y){ //这里的x,y分别是将以o为根的树切开后第一个新子树的根和第二个新子树的根
  2. if(!o) x=y=;
  3. else {
  4. if(val[o]<=k)
  5. x=o,split(ch[o][],k,ch[o][],y);
  6. else
  7. y=o,split(ch[o][],k,x,ch[o][]);
  8. pushup(o);
  9. }
  10. }

对于我们遍历到每一个点,假如它的权值小于k,那么它的所有左子树,都要分到左边的树里,然后遍历它的右儿子。假如大于k,把它的所有右子树分到右边的树里,遍历左儿子。

因为它的最多操作次数就是一直分到底,效率就是 $O(logn)$。

对于前k个版的,就是像找第k大的感觉。每次减掉sze

  1. void split(int now,int k,int &x,int &y){
  2. if (!now) x=y=;
  3. else{
  4. if (k<=siz[ch[now][]])
  5. y=now,split(ch[now][],k,x,ch[now][]);
  6. else
  7. x=now,split(ch[now][],k-sze[ch[now][]]-,ch[now][],y);
  8. pushup(now);
  9. }
  10. }

2、$merge$

这个就是把两个 $Treap$ 合成一个,保证第一个的权值小于第二个。

因为第一个 $Treap$ 的权值都比较小,我们比较一下它的 $prio$ (优先级),假如第一个的 $prio$ 小,我们就可以直接保留它的所有左子树,接着把第一个 $Treap$ 变成它的右儿子。反之,我们可以保留第二棵的所有右子树,指针指向左儿子。

你可以把这个过程形象的理解为在第一个 $ Treap$ 的右子树上插入第二个树,也可以理解为在第二个树的左子树上插入第一棵树。因为第一棵树都满足小于第二个树,所以就变成了比较 $prio$ 来确定树的形态。

也就是说,我们其实是遍历了第一个$Treap$ 的根->最大节点,第二个$Treap$的根->最小节点,也就是 $O(logn)$

  1. int merge(int x,int y){
  2. if(!x or !y) return x+y;
  3. if(prio[x]<prio[y]){
  4. ch[x][]=merge(ch[x][],y);
  5. pushup(x);
  6. return x;
  7. }
  8. else{
  9. ch[y][]=merge(x,ch[y][]);
  10. pushup(y);
  11. return y;
  12. }
  13. }

下面我们就可以通过这两个基本的东西实现各种各样的操作了。

3、insert

插入一个权值为 $k$ 的点,把树按照 $k$ 的权值 $split$ 成两个,再 $merge$ 回去。

4、remove

删除权值为 $k$ 的点,把树按照 $k$ 分成两个$a,b$ 再把$a$ 按照 $k-1$ 分成$c,d$。把$d$ 的两个儿子 $merge$起来,再 $merge(merge(c,d),b)$

  1. void remove(int k){
  2. int x,y,z;
  3. split(Root,k,x,y);
  4. split(x,k-,x,z);
  5. z=merge(ch[z][],ch[z][]);
  6. Root=merge(x,merge(z,y));
  7. }

其它见代码

  1. // 普通平衡树 fhq_Treap
  2. // By YoungNeal
  3. #include<cstdio>
  4. #include<cstdlib>
  5. #define N 100005
  6. #define inf 0x3f3f3f3f
  7.  
  8. int Root;
  9. int n,opt,x,tot;
  10. int val[N],prio[N];
  11. int sze[N],ch[N][];
  12.  
  13. void pushup(int o){
  14. sze[o]=sze[ch[o][]]+sze[ch[o][]]+;
  15. }
  16.  
  17. void split(int o,int k,int &x,int &y){
  18. if(!o) x=y=;
  19. else {
  20. if(val[o]<=k)
  21. x=o,split(ch[o][],k,ch[o][],y);
  22. else
  23. y=o,split(ch[o][],k,x,ch[o][]);
  24. pushup(o);
  25. }
  26. }
  27.  
  28. int merge(int x,int y){
  29. if(!x or !y) return x+y;
  30. if(prio[x]<prio[y]){
  31. ch[x][]=merge(ch[x][],y);
  32. pushup(x);
  33. return x;
  34. }
  35. else{
  36. ch[y][]=merge(x,ch[y][]);
  37. pushup(y);
  38. return y;
  39. }
  40. }
  41.  
  42. int newnode(int v){
  43. sze[++tot]=;
  44. val[tot]=v;
  45. prio[tot]=rand();
  46. return tot;
  47. }
  48.  
  49. void insert(int k){
  50. int x,y;
  51. split(Root,k,x,y);
  52. Root=merge(merge(x,newnode(k)),y);
  53. }
  54.  
  55. void remove(int k){
  56. int x,y,z;
  57. split(Root,k,x,y);
  58. split(x,k-,x,z);
  59. z=merge(ch[z][],ch[z][]);
  60. Root=merge(x,merge(z,y));
  61. }
  62.  
  63. void kthrank(int k){
  64. int x,y;
  65. split(Root,k-,x,y);
  66. printf("%d\n",sze[x]+);
  67. Root=merge(x,y);
  68. }
  69.  
  70. int rank(int o,int k){
  71. if(sze[ch[o][]]==k-) return val[o];
  72. if(sze[ch[o][]]>=k) return rank(ch[o][],k);
  73. return rank(ch[o][],k-sze[ch[o][]]-);
  74. }
  75.  
  76. void prev(int k){
  77. int x,y;
  78. split(Root,k-,x,y);
  79. printf("%d\n",rank(x,sze[x]));
  80. Root=merge(x,y);
  81. }
  82.  
  83. void nxt(int k){
  84. int x,y;
  85. split(Root,k,x,y);
  86. printf("%d\n",rank(y,));
  87. Root=merge(x,y);
  88. }
  89.  
  90. signed main(){
  91. scanf("%d",&n);
  92. while(n--){
  93. scanf("%d%d",&opt,&x);
  94. if(opt==) insert(x);
  95. if(opt==) remove(x);
  96. if(opt==) kthrank(x);
  97. if(opt==) printf("%d\n",rank(Root,x));
  98. if(opt==) prev(x);
  99. if(opt==) nxt(x);
  100. }
  101. return ;
  102. }

5、区间操作

对于翻转区间 $[l,r]$,我们可以先把区间 $[1,l-1]$ $split$ 出来,再把 $[l,r]$ $split$ 出来就行了。注意 $lazy$ 标记及时清除。

  1. // 文艺平衡树 fhp_Treap
  2. // By YoungNeal
  3. #include<ctime>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #define N 100005
  7.  
  8. int Root;
  9. int lazy[N];
  10. int n,m,cnt;
  11. int val[N],sze[N];
  12. int ch[N][],prio[N];
  13.  
  14. void pushup(int o){
  15. sze[o]=sze[ch[o][]]+sze[ch[o][]]+;
  16. }
  17.  
  18. void pushdown(int o){
  19. if(!lazy[o] or !o) return;
  20. ch[o][]^=ch[o][]^=ch[o][]^=ch[o][];
  21. lazy[ch[o][]]^=;
  22. lazy[ch[o][]]^=;
  23. lazy[o]=;
  24. }
  25.  
  26. void split(int o,int k,int &x,int &y){
  27. if(!o) x=y=;
  28. else{
  29. pushdown(o);
  30. if(k>sze[ch[o][]]) x=o,split(ch[o][],k-sze[ch[o][]]-,ch[o][],y);
  31. else y=o,split(ch[o][],k,x,ch[o][]);
  32. pushup(o);
  33. }
  34. }
  35.  
  36. int merge(int x,int y){
  37. if(!x or !y) return x+y;
  38. pushdown(x); pushdown(y);
  39. if(prio[x]<prio[y]){
  40. ch[x][]=merge(ch[x][],y);
  41. pushup(x);
  42. return x;
  43. }
  44. else{
  45. ch[y][]=merge(x,ch[y][]);
  46. pushup(y);
  47. return y;
  48. }
  49. }
  50.  
  51. int newnode(int v){
  52. val[++cnt]=v;
  53. sze[cnt]=;
  54. prio[cnt]=rand();
  55. return cnt;
  56. }
  57.  
  58. void res(int l,int r){
  59. int a,b,c,d;
  60. split(Root,r,a,b);
  61. split(a,l-,c,d);
  62. lazy[d]^=;
  63. Root=merge(merge(c,d),b);
  64. }
  65.  
  66. void dfs(int now){
  67. if(!now) return;
  68. pushdown(now);
  69. dfs(ch[now][]);
  70. printf("%d ",val[now]);
  71. dfs(ch[now][]);
  72. }
  73.  
  74. signed main(){
  75. srand(time());
  76. scanf("%d%d",&n,&m);
  77. for(int i=;i<=n;i++)
  78. Root=merge(Root,newnode(i));
  79. //printf("Root=%d\n",Root);
  80. for(int x,y,i=;i<=m;i++){
  81. scanf("%d%d",&x,&y);
  82. res(x,y);
  83. //printf("i=%d\n",i);
  84. //dfs(Root);
  85. }
  86. //printf("Root=%d\n",Root);
  87. dfs(Root);
  88. return ;
  89. }

[总结] fhq_Treap 学习笔记的更多相关文章

  1. fhq_treap 学习笔记

    前言:昨天写NOIp2017队列,写+调辗转了3h+,不知道怎么的,就点进了一个神仙的链接,便在今日学习了神仙的fhq_treap. 简介:fhq_treap功能强大,支持splay支持的所有操作,代 ...

  2. Treap与fhq_Treap学习笔记

    1.普通Treap 通过左右旋来维护堆的性质 左右旋是不改变中序遍历的 #include<algorithm> #include<iostream> #include<c ...

  3. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  7. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  8. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  9. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

随机推荐

  1. tar命令-vi编辑器-磁盘分区及格式化-软链接及硬链接文件

    一.tar命令 1.将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/1.txt(覆盖) [root@localhost  /] #  cat  /etc/passwd  /etc/group ...

  2. uva 10917 Walk Through The Forest

    题意: 一个人从公司回家,他可以从A走到B如果从存在从B出发到家的一条路径的长度小于任何一条从A出发到家的路径的长度. 问这样的路径有多少条. 思路: 题意并不好理解,存在从B出发到家的一条路径的长度 ...

  3. 小技巧-C#文本快速删除空行

    查找:^\s*\n 替换空格 选择正则表达式

  4. 有些ES6方法极简,但是性能不够好

    So,也许你觉得ES6让你视野大开,但是并不是性能也能跟得上~ 首先,让我们先来一个简单的性能测试: 数组去重 es5写法: function delSame(arr){ var n = []; ; ...

  5. Spring Cloud学习笔记-009

    API网关服务:Spring Cloud Zuul API网关是一个更为智能的应用服务器,它的定义类似于面向对象设计模式中的Façade模式,它的存在就像是整个微服务架构系统的门面一样,所有的外部客户 ...

  6. java--Iterator迭代问题:集合并发访问异常

    用Iterator对数组进行迭代后,如果在迭代过程中对数组进行增加元素操作(这里iterator本身没有提供增加操作方法)时,就会抛出并发访问异常: 异常如下: Exception in thread ...

  7. ognl版本错误

    错误信息: 2014-2-6 21:20:10 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() fo ...

  8. Java数据类型与SQL数据类型的映射

    Java数据类型与SQL数据类型的映射 SQL Data Type Java Data Type char/varchar/longvarchar String numeric/decimal jav ...

  9. [CODEVS 1288]埃及分数

    Description 在古埃及,人们使用单位分数的和(形如1/a的, a是自然数)表示一切有理数. 如:2/3=1/2+1/6,但不允许2/3=1/3+1/3,因为加数中有相同的. 对于一个分数a/ ...

  10. 冰精冻西瓜[P3787洛谷]

    题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有根树,琪露诺想要把它们冷冻起来慢慢吃. 这些西瓜蔓具有神奇的性质,可以将经过它的 ...