[转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
转载自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182491.html
今天我们来学习一种新的数据结构:无旋treap。它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化。
无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我们还是用rand()来实现平衡
而无旋treap与treap不同的地方,也是其核心,就是它不旋转用两个新的核心函数:merge函数(合并两棵子树)和split函数(分裂出某棵树的前k个节点,并且作为一棵树返回)
首先看merge函数,它是一个递归实现的过程,先看代码:
1 Treap *merge(Treap *a,Treap *b)
2 {
3 if(a==null)return b;
4 if(b==null)return a;
5 pushdown(a);pushdown(b);
6 if(a->key < b->key)
7 {a->ch[1]=merge(a->ch[1],b);a->update();return a;}
8 else
9 {b->ch[0]=merge(a,b->ch[0]);b->update();return b;}
10 }
对于两棵子树a和b,我们可以实现把b树合并到a树中
在合并时,我们首先看他们的根节点谁的键值比较小(我维护的是一个小根堆),并且建立对应的父子关系。
又由于平衡树的中序遍历不变,我们又要把b插在a后面,维持一个确定的中序遍历,
所以我们应该一直把a作为merge函数的前一个参数,b作为后一个参数,这个顺序不能换.
这一个确定的顺序的重要性尤其体现在后续的区间操作中。刚开始的时候可以当板子背下来,但随着打题肯定会逐渐理解。
接下来我们介绍split函数,这也是一个递归实现的过程,还是先看代码:
1 typedef pair<Treap*,Treap*> D;
2 D split(Treap *o,int k)
3 {
4 if(o==null) return D(null,null);
5 D y;pushdown(o);
6 if(o->ch[0]->size>=k)
7 {y=split(o->ch[0],k);o->ch[0]=y.second;o->update();y.second=o;}
8 else
9 {y=split(o->ch[1],k-o->ch[0]->size-1);o->ch[1]=y.first;o->update();y.first=o;}
10 return y;
11 }
我们首先定义一个pair,这样做的好处是同时返回分裂出来的两棵树的根节点指针,我规定第一个是分离完成的树,第二个是剩下的原树。
然后考虑分离前k个的过程:如果o的左儿子有k个以上节点,我们显然应该去左儿子分离。
然后我们会得到分离完成的树和左儿子剩下的树,这时候把左儿子剩下的部分接回节点o,并把新的o作为分离o剩下的原树
如果左儿子节点个数不够,我们就去右儿子分离,过程是相似的,但略有不同,留给读者思考。
有了这两个函数,我们就可以用他们实现一些常用的操作了,比如:
insert=split+newnode+merge+merge
delete=split+split+merge(合并第一个split的first和第二个的second)
等等,其他操作也可以用类似的思路打出来。下面我们用一道例题实战一下。建议读者自己实现代码并充分思考后再核对标程。
3224: Tyvj 1728 普通平衡树
Time Limit: 10 Sec Memory Limit: 128 MB
Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
84185
492737
HINT
1 #include <cstdio>
2 #include <algorithm>
3 #include <cstring>
4 #include <ctime>
5 #include <cstdlib>
6 using namespace std;
7 const int maxn=100100,inf=0x7fffffff;
8 struct Treap
9 {
10 Treap* ch[2];
11 int key,val,size;
12 Treap(int v)
13 {size=1,val=v,key=rand();ch[0]=ch[1]=NULL;}
14 inline void tain()
15 {size=1+(ch[0]?ch[0]->size:0)+(ch[1]?ch[1]->size:0);}
16 }*root;
17 typedef pair<Treap*,Treap*> D;
18 inline int size(Treap *o){return o?o->size:0;}
19 Treap *Merge(Treap *a,Treap* b)
20 {
21 if(!a)return b;
22 if(!b)return a;
23 if(a->key < b->key)
24 {a->ch[1]=Merge(a->ch[1],b);a->tain();return a;}
25 else
26 {b->ch[0]=Merge(a,b->ch[0]);b->tain();return b;}
27 }
28 D Split(Treap *o,int k)
29 {
30 if(!o)return D(NULL,NULL);
31 D y;
32 if(size(o->ch[0])>=k)
33 {y=Split(o->ch[0],k);o->ch[0]=y.second;o->tain();y.second=o;}
34 else
35 {y=Split(o->ch[1],k-size(o->ch[0])-1);o->ch[1]=y.first;o->tain();y.first=o;}
36 return y;
37 }
38 int Getkth(Treap *o,int v)
39 {
40 if(o==NULL)return 0;
41 return(o->val>=v)?Getkth(o->ch[0],v):Getkth(o->ch[1],v)+size(o->ch[0])+1;
42 }
43 inline int Findkth(int k)
44 {
45 D x=Split(root,k-1);
46 D y=Split(x.second,1);
47 Treap *ans=y.first;
48 root=Merge(Merge(x.first,ans),y.second);
49 return ans!=NULL?ans->val:0;
50 }
51 inline void Insert(int v)
52 {
53 int k=Getkth(root,v);
54 D x=Split(root,k);
55 Treap *o=new Treap(v);
56 root=Merge(Merge(x.first,o),x.second);
57 }
58 void Delete(int v)
59 {
60 int k=Getkth(root,v);
61 D x=Split(root,k);
62 D y=Split(x.second,1);
63 root=Merge(x.first,y.second);
64 }
65 int main(){
66 int m,opt,x;scanf("%d",&m);
67 while(m--)
68 {
69 scanf("%d%d",&opt,&x);
70 switch(opt)
71 {
72 case 1:Insert(x);break;
73 case 2:Delete(x);break;
74 case 3:printf("%d\n",Getkth(root,x)+1);break;
75 case 4:printf("%d\n",Findkth(x));break;
76 case 5:printf("%d\n",Findkth(Getkth(root,x)));break;
77 case 6:printf("%d\n",Findkth(Getkth(root,x+1)+1));break;
78 }
79 }
80 }
[转载]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)的更多相关文章
- [转载]无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )
转自ZZH大佬,原文:http://www.cnblogs.com/LadyLex/p/7182631.html 1500: [NOI2005]维修数列 Time Limit: 10 Sec Mem ...
- [您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)
今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我 ...
- [您有新的未分配科技点] 无旋treap:从单点到区间(例题 BZOJ1500&NOI2005 维护数列 )
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MB Description Input 输入的第1 行包含两个数N 和M(M ≤20 ...
- [Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护 ...
- [Bzoj3224][Tyvj1728] 普通平衡树(splay/无旋Treap)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3224 平衡树入门题,学习学习. splay(学习yyb巨佬) #include<b ...
- Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 https://www.luogu.org/problemnew/show/P3 ...
- 【算法学习】Fhq-Treap(无旋Treap)
Treap——大名鼎鼎的随机二叉查找树,以优异的性能和简单的实现在OIer们中广泛流传. 这篇blog介绍一种不需要旋转操作来维护的Treap,即无旋Treap,也称Fhq-Treap. 它的巧妙之处 ...
- 无旋treap的区间操作实现
最近真的不爽...一道维修数列就做了我1上午+下午1h+1晚上+晚上1h+上午2h... 一道不错的自虐题... 由于这一片主要讲思想,代码我放这里了 不会无旋treap的童鞋可以进这里 呵呵... ...
- 无旋treap的简单思想以及模板
因为学了treap,不想弃坑去学splay,终于理解了无旋treap... 好像普通treap没卵用...(再次大雾) 简单说一下思想免得以后忘记.普通treap因为带旋转操作似乎没卵用,而无旋tre ...
随机推荐
- Chapter 3. Video Coding Concepts
本章主要介绍一些有关视频编码的概念 时域模型(Temporal Model) 时域模型的作用是去除帧间冗余.如:将第二帧减去第一帧,得到的剩余信息,其能量会远小于第二帧本身. 基于块的运动估计和补偿 ...
- 传输层socket通讯之java实现
使用流套接字来示例一个客户/服务器的应用.客户端的应用连接到服务器上面,服务端的应用发送数据到客户端,然后客户将收到的数据显示出来. 服务端代码: package socket; import jav ...
- 如何简单的实现新手引导之UGUI篇
一个完整的游戏项目肯定是要做新手引导的,而引导做的好坏可能会影响玩家的留存.那么怎么简单的实现个简有效的引导呢!先不说废话,先看看效果,这是一个基于UGUI做的一个简单的引导! 怎么样,看着是那么回事 ...
- easyui(一) 初始easyui
中午贪睡,睡到3点多,爬起来赶紧学习,学习是我快乐(自我催眠).哈哈~ --WH 一.什么是easyui? 学习一个东西,最重要的是知道它的定位(是干嘛的,基本的用法是什么,快速入门),其实easyu ...
- Ubantu 16.4 samba安装配置
本文总结了Ubantu 16.04 环境下的samba安装.配置及使用.本文为原创,也是我的第一篇博客,以后会经常写博客,记录自己的学习.总结及研究,让博客见证着我成长的轨迹. 下文中的所有命令均使用 ...
- 数据库--释放mysql数据库资源
背景 nikeodong之前做了项目的数据库主从,在全备的过程发现数据库是越来越大了:最后发现是资源不释放的问题. 目的 为了解决mysql资源不释放的问题. 步骤 1.vim /etc/my.cnf ...
- App 组件化/模块化之路——构建开发架构思路
App 组件化/模块化开发架构思路 随着业务的发展 App 开发技术也越来越成熟,对开发者来说 App 代码量也迅速地增长到一个数量级.对于如何架构 App 已经每个开发者面临的实际问题.好的架构可以 ...
- Asp.net管理信息系统中数据统计功能的实现
数据统计是每个系统中必备的功能,在给领导汇报统计数据,工作中需要的进展数据时非常有用. 在我看来,一个统计的模块应该实现以下功能: 能够将常用的查询的统计结果显示出来: 显示的结果可以是表格形式,也可 ...
- windows调试工具列表
摘自windbg帮助文档(windbg中输入.hh): Debugging Tools for Windows (安装WinDbg后这些工具都会安装在目录C:\Program Files (x86)\ ...
- 单片机C语言基础编程源码六则2
1.某单片机系统的P2口接一数模转换器DAC0832输出模拟量,现在要求从DAC0832输出连续的三角波,实现的方法是从P2口连续输出按照三角波变化的数值,从0开始逐渐增大,到某一最大值后逐渐减小,直 ...