无旋treap的简单思想以及模板
2017-07-31 22:22
253 查看
因为学了treap,不想弃坑去学splay,终于理解了无旋treap...
好像普通treap没卵用。。。(再次大雾)
简单说一下思想免得以后忘记。普通treap因为带旋转操作似乎没卵用,而无旋treap可以不旋转。
经典地不能再经典的例题
插入x数
删除x数(若有多个相同的数,因只删除一个)
查询x数的排名(若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数)
求x的后继(后继定义为大于x,且最小的数)
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
输出样例#1:
1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
无旋treap最基本的操作就是merge和split。修改都得靠这个。首先说一下merge和split的操作方法。
merge:给你两个平衡树a和b,让你合并它们,但b中所有权值都得大于a中所有权值以维护treap性质。如果是tree只需要建个根节点然后连两条边,但无法维护heap性质。其实操作也很简单,如果a的rand值小于b的rand值,则merge(a.rs,b),否则merge(a,b.ls)。
split:将平衡树a分成两个,一个是1~K名,一个是K+1~size名,返回两个树的根,我存在了一个pair中。记左子树size为s,如果k==s则两根就是左儿子和根,如果k==s+1则两根就是根和右儿子。若都不是,继续向下递归,那个就参照以下查询排名的操作。注意split要将儿子设为0
那么基本操作怎么实现???
查询排名、查询排名为x的数、查询前驱后继代码基本不变,只是要注意这里需要合并分离所以不可以记录出现次数要新开一个数,否则后果自行脑补。
插入操作:先查询这个数x的排名K,然后把treap分成两个treap,即执行split(root,K),得到两根a,b。再合并两次,即执行root=merge(a,点的新编号),root=merge(root,b)(注意要重设root)
删除操作:也差不多。先查询排名K,然后把treap分成三个treap,分别为a=1~K-1,b=K,c=K+1~n,要删去K,只需再合并a,c子树即可
不旋转应该就可以维护一些别的好东西了
然而并不会
然后附上普通平衡树的AC代码:
View Code
[b] 还有一篇博客代码写的不错,这是链接
好像普通treap没卵用。。。(再次大雾)
简单说一下思想免得以后忘记。普通treap因为带旋转操作似乎没卵用,而无旋treap可以不旋转。
经典地不能再经典的例题
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:插入x数
删除x数(若有多个相同的数,因只删除一个)
查询x数的排名(若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数)
求x的后继(后继定义为大于x,且最小的数)
输入输出格式
输入格式:第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
输出格式:
对于操作3,4,5,6每行输出一个数,表示对应答案
输入输出样例
输入样例#1:10 1 106465 4 1 1 317721 1 460929 1 644985 1 84185 1 89851 6 81968 1 492737 5 493598
输出样例#1:
106465 84185 492737
说明
时空限制:1000ms,128M1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
无旋treap最基本的操作就是merge和split。修改都得靠这个。首先说一下merge和split的操作方法。
merge:给你两个平衡树a和b,让你合并它们,但b中所有权值都得大于a中所有权值以维护treap性质。如果是tree只需要建个根节点然后连两条边,但无法维护heap性质。其实操作也很简单,如果a的rand值小于b的rand值,则merge(a.rs,b),否则merge(a,b.ls)。
split:将平衡树a分成两个,一个是1~K名,一个是K+1~size名,返回两个树的根,我存在了一个pair中。记左子树size为s,如果k==s则两根就是左儿子和根,如果k==s+1则两根就是根和右儿子。若都不是,继续向下递归,那个就参照以下查询排名的操作。注意split要将儿子设为0
那么基本操作怎么实现???
查询排名、查询排名为x的数、查询前驱后继代码基本不变,只是要注意这里需要合并分离所以不可以记录出现次数要新开一个数,否则后果自行脑补。
插入操作:先查询这个数x的排名K,然后把treap分成两个treap,即执行split(root,K),得到两根a,b。再合并两次,即执行root=merge(a,点的新编号),root=merge(root,b)(注意要重设root)
删除操作:也差不多。先查询排名K,然后把treap分成三个treap,分别为a=1~K-1,b=K,c=K+1~n,要删去K,只需再合并a,c子树即可
不旋转应该就可以维护一些别的好东西了
然而并不会
然后附上普通平衡树的AC代码:
// It is made by XZZ #include<cstdio> #include<algorithm> using namespace std; #define rep(a,b,c) for(rg int a=b;a<=c;a++) #define drep(a,b,c) for(rg int a=b;a>=c;a--) #define erep(a,b) for(rg int a=fir;a;a=nxt[a]) #define il inline #define rg register #define vd void #define mp make_pair typedef long long ll; il int gi(){ rg int x=0,f=1;rg char ch=getchar(); while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar(); while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*f; } #define Now tree[now] struct node{int ls,rs,value,rand,size;}tree[100010]; int root,siz; int seed=151806+150605+151127;//mou shen ben xue hao+mou da lao xue hao+mou ju ruo xue hao il int Rand(){return seed=seed*48271%2147483647;} il vd reset(int now){Now.size=tree[Now.ls].size+tree[Now.rs].size+1;} il int merge(int a,int b){ if(!a||!b)return a|b; if(tree[a].rand<tree[b].rand){tree[a].rs=merge(tree[a].rs,b),reset(a);return a;} else {tree[b].ls=merge(a,tree[b].ls),reset(b);return b;} } il pair<int,int>split(int now,int num){ if(!now)return mp(0,0); int ls=Now.ls,rs=Now.rs; if(num==tree[ls].size){Now.ls=0,reset(now);return mp(ls,now);} if(num==tree[ls].size+1){Now.rs=0,reset(now);return mp(now,rs);} if(num<tree[ls].size){ pair<int,int>T=split(ls,num); Now.ls=T.second,reset(now); return mp(T.first,now); }else{ pair<int,int>T=split(rs,num-tree[ls].size-1); Now.rs=T.first,reset(now); return mp(now,T.second); } } il int getrank(int now,int num){ int ret=0,t=1e9; while(now){ if(num==Now.value)t=min(t,ret+tree[Now.ls].size+1); if(num<=Now.value)now=Now.ls; else ret+=tree[Now.ls].size+1,now=Now.rs; } return t==1e9?ret:t; } il int getnum(int now,int num){ while(1){ if(tree[Now.ls].size==num-1)return Now.value; if(tree[Now.ls].size>num-1)now=Now.ls; else num-=tree[Now.ls].size+1,now=Now.rs; } } il int lower(int now,int num){ int ret; while(now)if(tree[now].value<num)ret=tree[now].value,now=Now.rs; else now=Now.ls; return ret; } il int upper(int now,int num){ int ret; while(now)if(tree[now].value>num)ret=tree[now].value,now=Now.ls; else now=Now.rs; return ret; } il vd ins(int num){ int Rank=getrank(root,num),now; pair<int,int>tmp=split(root,Rank); now=++siz; Now.value=num,Now.rand=Rand(),Now.size=1; root=merge(tmp.first,siz); root=merge(root,tmp.second); } il vd del(int num){ int Rank=getrank(root,num); pair<int,int>t1=split(root,Rank),t2=split(t1.first,Rank-1); root=merge(t2.first,t1.second); } int main(){ int n=gi(),opt,x; while(n--){ opt=gi(),x=gi(); switch(opt){ case 1:ins(x);break; case 2:del(x);break; case 3:printf("%d\n",getrank(root,x));break; case 4:printf("%d\n",getnum(root,x));break; case 5:printf("%d\n",lower(root,x));break; case 6:printf("%d\n",upper(root,x));break; } } return 0; }
View Code
[b] 还有一篇博客代码写的不错,这是链接
相关文章推荐
- Revit二次开发winform简单的标准模板以及wpf简单的标准模板
- 泛型编程、STL的概念、STL模板思想及其六大组件的关系,以及泛型编程(GP)、STL、面向对象编程(OOP)、C++之间的关系
- 初学者看过来:简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系。
- Java_Ant_Web Project完整build.xml文件模板以及Strust2简单示例;
- 初学者看过来:简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系。
- 简单的自定义实现Stack模板(顺序栈以及链式栈没有迭代器和销毁)
- wbs简单介绍以及相关模板截图
- 使用ireport设计jasperreport报表模板,以及简单的设计使用案例
- 关于字符串判断的几个常用属性 以及简单项目实现中数组运用的初步思想 蓝懿教育
- 简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系。
- 利用 c++模板 类型 推导思想,实现最简单的 判断两个类型 是否一样的 方法
- cordova 插件编写 以及 简单模板
- 简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系
- 一个超级简单的HTML模板框架源代码以及使用示例
- 初学者看过来:简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系
- Java 学习笔记10:获取POST数据以及简单模板输出
- 类模板作为函数参数以及作为类模板参数的一个简单示例
- 模板之string类型相加,以及指针
- 上海办公室装修公司教你瓷砖的选择以及瓷砖的简单分类
- C语言简单通讯录模板