定义
树堆,在数据结构中也称Treap,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。
简单点说,Treap=tree+heap
实现
Treap实际上是对BST的优化。因为BST有可能退化成链而导致查询复杂度变成 O(n) ,而Treap多了heap这个性质,使得它的期望复杂度可以达到 O(nlog2n)
而维护heap时需要旋转操作,这里给一张图体会一下:
那heap这个性质是怎么来的呢?
在插入一个节点时,我们随机地给它一个优先级,然后和维护heap一样维护这个优先级。插入时如果优先级比根大就旋转。删除时和插入反过来就可以了,把需要删除的节点不断旋转至叶子节点,然后删去即可。
操作
由于Treap的本质就是BST,因此它支持BST的所有操作。
代码实现(模板)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define N 100000
using namespace std;
struct node{
int w,p,size,rnd,to[2];
//w:权值 p:有多少权值是相等的 size:子树中的节点个数
//rnd:优先级 to[]:儿子
}t[N+5];
int n,rt,nd,p;
void rtt(int &x,int fl){//rotate(旋转)
int s=t[x].to[fl];
t[x].to[fl]=t[s].to[fl^1];
t[s].to[fl^1]=x;
t[s].size=t[x].size;
t[x].size=t[t[x].to[0]].size+t[t[x].to[1]].size+t[x].p;
x=s; return;
}
void nsrt(int &x,int w){//insert(插入)
if (!x){
t[x=++nd].w=w;
t[x].rnd=rand();
t[x].p=t[x].size=1;
return;
}
t[x].size++;
if (t[x].w==w) t[x].p++;
else if (t[x].w<w){
nsrt(t[x].to[1],w);
if (t[t[x].to[1]].rnd<t[x].rnd) rtt(x,1);
}
else{
nsrt(t[x].to[0],w);
if (t[t[x].to[0]].rnd<t[x].rnd) rtt(x,0);
}
}
void dlt(int &x,int w){//delete(删除)
if (!x) return;
if (t[x].w==w){
if (t[x].p>1){ t[x].p--; t[x].size--; return; }
if (!(t[x].to[0]*t[x].to[1])) x=t[x].to[0]+t[x].to[1];
else if (t[t[x].to[0]].rnd<t[t[x].to[1]].rnd) rtt(x,0),dlt(x,w);
else rtt(x,1),dlt(x,w);
}
else{
t[x].size--;
if (t[x].w<w) dlt(t[x].to[1],w);
else dlt(t[x].to[0],w);
}
}
int srch_rk(int x,int w){//search_rank(查询排名)
if (!x) return 0;
if (t[x].w==x) return t[t[x].to[0]].size+1;
else if (t[x].w<w)
return t[t[x].to[0]].size+t[x].p+srch_rk(t[x].to[1],w);
else return srch_rk(t[x].to[0],w);
}
int srch_nm(int x,int w){//search_num(查询数)
if (!x) return 0;
if (t[t[x].to[0]].size>=w)
return srch_nm(t[x].to[0],w);
else if (t[t[x].to[0]].size+t[x].p<w)
return srch_nm(t[x].to[1],w-t[t[x].to[0]].size-t[x].p);
else return t[x].w;
}
int srch_frnt(int x,int w){//search_front(查询前驱)
if (!x) return 0;
if (t[x].w<w){
int k=srch_frnt(t[x].to[1],w);
if (!k) return t[x].w;
else return k;
}
else return srch_frnt(t[x].to[0],w);
}
int srch_bck(int x,int w){//search_back(查询后继)
if (!x) return 0;
if (t[x].w>w){
int k=srch_bck(t[x].to[0],w);
if (!k) return t[x].w;
else return k;
}
else return srch_bck(t[x].to[1],w);
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
int flag,x;
scanf("%d%d",&flag,&x);
switch (flag){
case 1: nsrt(rt,x); break;
case 2: dlt(rt,x); break;
case 3: printf("%d\n",srch_rk(rt,x)+1); break;//这里记得+1
case 4: printf("%d\n",srch_nm(rt,x)); break;
case 5: printf("%d\n",srch_frnt(rt,x)); break;
case 6: printf("%d\n",srch_bck(rt,x)); break;
}
}
return 0;
}