无旋treap的简单思想以及模板

因为学了treap,不想弃坑去学splay,终于理解了无旋treap...

好像普通treap没卵用。。。(再次大雾)

简单说一下思想免得以后忘记。普通treap因为带旋转操作似乎没卵用,而无旋treap可以不旋转。

经典地不能再经典的例题

 

题目描述

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个)

  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数)

  6. 求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,128M

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代码:

 // 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[b];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=,f=;rg char ch=getchar();
while(ch<''||ch>'')f=ch=='-'?-:f,ch=getchar();
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x*f;
}
#define Now tree[now]
struct node{int ls,rs,value,rand,size;}tree[];
int root,siz;
int seed=++;//mou shen ben xue hao+mou da lao xue hao+mou ju ruo xue hao
il int Rand(){return seed=seed*%;}
il vd reset(int now){Now.size=tree[Now.ls].size+tree[Now.rs].size+;}
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(,);
int ls=Now.ls,rs=Now.rs;
if(num==tree[ls].size){Now.ls=,reset(now);return mp(ls,now);}
if(num==tree[ls].size+){Now.rs=,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-);
Now.rs=T.first,reset(now);
return mp(now,T.second);
}
}
il int getrank(int now,int num){
int ret=,t=1e9;
while(now){
if(num==Now.value)t=min(t,ret+tree[Now.ls].size+);
if(num<=Now.value)now=Now.ls;
else ret+=tree[Now.ls].size+,now=Now.rs;
}
return t==1e9?ret:t;
}
il int getnum(int now,int num){
while(){
if(tree[Now.ls].size==num-)return Now.value;
if(tree[Now.ls].size>num-)now=Now.ls;
else num-=tree[Now.ls].size+,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=;
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-);
root=merge(t2.first,t1.second);
}
int main(){
int n=gi(),opt,x;
while(n--){
opt=gi(),x=gi();
switch(opt){
case :ins(x);break;
case :del(x);break;
case :printf("%d\n",getrank(root,x));break;
case :printf("%d\n",getnum(root,x));break;
case :printf("%d\n",lower(root,x));break;
case :printf("%d\n",upper(root,x));break;
}
}
return ;
}

还有一篇博客代码写的不错,这是链接

上一篇:[BZOJ3223]文艺平衡树 无旋Treap


下一篇:H5案例分享:html5移动开发细微之美