作用
一种平衡树,可以只利用合并与拆分两种操作实现插入删除等所有二叉查找树可以做的事情.
实现方法
treap=tree+heap,利用tree来保持二叉查找树的功能,再利用heap来保证它是平衡树.
每个节点保存两个值,一个是题目给出的,要储存的值,还有一个是rand的且长期不变,建树时储存的值根据二叉查找树的性质来保存,同时保证rand()的值符合堆的性质,每个根为该子树的极值,这样就可以保证树的平衡.
对于平衡树的各种操作,只要灵活利用下述两种操作都可以实现
合并
合并时,要储存的值较小的树一定在另外一棵树的左边,因此只要通过递归实现较小树右边这条链和较大树左边这条链的合并即可.
int mg(int u,int v)
{
if(!u||!v) return u+v;
int res;
if(node[u].ran<node[v].ran)
{
node[u].right_son=mg(node[u].right_son,v);
up(u);
return u;
}
node[v].left_son=mg(u,node[v].left_son);
up(v);
return v;
}
拆分
就是查找中序遍历第k个的节点,然后将中序遍历小于等于它的与大于他的节点分成两棵树,同样也可以递归实现.
#define P pair<int,int>
#define mp make_pair<int,int>
#define fi first
#define se second
P spl(int u,int v)
{
if(!v) return mp(0,u);
if(v==node[u].size) return mp(u,0);
int tmp;
P res;
if(v==node[node[u].left_son].size+1)
{
tmp=node[u].right_son;
node[u].right_son=0;
up(u);
return mp(u,tmp);
}
if(v==node[node[u].left_son].size)
{
tmp=node[u].left_son;
node[u].left_son=0;
up(u);
return mp(tmp,u);
}
if(v<node[node[u].left_son].size)
{
tmp=node[u].left_son;
node[u].left_son=0;
res=spl(tmp,v);
return mp(res.fi,mg(res.se,u));
}
tmp=node[u].right_son;
node[u].right_son=0;
res=spl(tmp,v-node[node[u].left_son].size-1);
return mp(mg(u,res.fi),res.se);
}
例题 codevs 1343 蚱蜢
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define C ch=getchar()
#define P pair<int,int>
#define mp make_pair<int,int>
#define fi first
#define se second
#define N 100100
using namespace std;
int n,m,rt;
char ch;
P a,b,c;
struct Node
{
int mx,num,ran,left_son,right_son,size;
}node[N];
inline void up(int u)
{
node[u].mx=max(node[node[u].left_son].mx,node[node[u].right_son].mx);
node[u].mx=max(node[u].mx,node[u].num);
node[u].size=node[node[u].left_son].size+node[node[u].right_son].size+1;
}
int mg(int u,int v)
{
if(!u||!v) return u+v;
int res;
if(node[u].ran<node[v].ran)
{
node[u].right_son=mg(node[u].right_son,v);
up(u);
return u;
}
node[v].left_son=mg(u,node[v].left_son);
up(v);
return v;
}
P spl(int u,int v)
{
if(!v) return mp(0,u);
if(v==node[u].size) return mp(u,0);
int tmp;
P res;
if(v==node[node[u].left_son].size+1)
{
tmp=node[u].right_son;
node[u].right_son=0;
up(u);
return mp(u,tmp);
}
if(v==node[node[u].left_son].size)
{
tmp=node[u].left_son;
node[u].left_son=0;
up(u);
return mp(tmp,u);
}
if(v<node[node[u].left_son].size)
{
tmp=node[u].left_son;
node[u].left_son=0;
res=spl(tmp,v);
return mp(res.fi,mg(res.se,u));
}
tmp=node[u].right_son;
node[u].right_son=0;
res=spl(tmp,v-node[node[u].left_son].size-1);
return mp(mg(u,res.fi),res.se);
}
int main()
{
srand(2333);
int i,j,p,q;
cin>>n>>m;
for(i=1;i<=n;i++)
{
scanf("%d",&p);
node[i].num=node[i].mx=p;
node[i].ran=rand();
node[i].size=1;
rt=mg(rt,i);
}
for(i=1;i<=m;i++)
{
scanf("%d",&p);
for(C;ch!='L'&&ch!='D';C);
scanf("%d",&q);
if(ch=='L')
{
a=spl(rt,p-1);
b=spl(a.se,1);
c=spl(a.fi,p-1-q);
printf("%d\n",node[c.se].mx);
rt=mg(c.fi,mg(b.fi,mg(c.se,b.se)));
continue;
}
a=spl(rt,p-1);
a=a;
b=spl(a.se,1);
c=spl(b.se,q);
printf("%d\n",node[c.fi].mx);
rt=mg(a.fi,mg(c.fi,mg(b.fi,c.se)));
}
}