Treap
简介
Treap(树堆)是一种 弱平衡 的 二叉搜索树.
Treap 的结点除了被维护的 权值()之外,还附加了一个随机的 优先级().其中,权值满足二叉搜索树性质,优先级满足堆性质(小根堆或大根堆).
其中,二叉搜索树的性质是指:
- 左子树所有节点的权值()比父节点小.
- 右子树所有节点的权值()比父节点大.
堆的性质是:
- 子节点优先级()比父节点大或小(取决于是小根堆还是大根堆).
思路
通过随机的优先级使得期望深度降为 \(O(logn)\) 级别
主要操作
旋转(rotate)
原理

作用
维护堆的性质
实现
void rotate(int &p,int d){//0:左旋 1:右旋
int tmp=ch[p][d^1];ch[p][d^1]=ch[tmp][d],ch[tmp][d]=p,p=tmp;
pushup(ch[p][d]),pushup(p);
}
插入(insert)
原理
先确保BST的性质,再通过旋转来维护堆的性质
实现
void insert(int &p,int v){
if(!p){create(p,v);return;}
if(v==val[p]){cnt[p]++;pushup(p);return;}
int d=(v>val[p]);
insert(ch[p][d],v);
if(rk[p]<rk[ch[p][d]]) rotate(p,d^1);
pushup(p);
}
删除(remove)
原理
将节点移动到叶子上再删除
实现
void remove(int &p,int v){
if(!p) return;
if(v==val[p]){
if(cnt[p]>1){cnt[p]--;pushup(p);return;}
if(ls||rs){
if(!rs||rk[ls]>rk[rs]) rotate(p,1),remove(rs,v);
else rotate(p,0),remove(ls,v);
pushup(p);
}else p=0;
return;
}
if(v<val[p]) remove(ls,v);
else remove(rs,v);
pushup(p);
}
例题
#include<bits/stdc++.h>
using namespace std;
#define ls ch[p][0]
#define rs ch[p][1]
const int N=1e6+5,inf=1e9;
int ch[N][2],val[N],cnt[N],rk[N],tot,siz[N],rt,n;
void create(int &p,int v){p=++tot,val[p]=v,cnt[p]=1,rk[p]=rand(),siz[p]=1;}
void pushup(int p){siz[p]=siz[ls]+siz[rs]+cnt[p];}
void build(){create(rt,-inf),create(ch[rt][1],inf),pushup(rt);}
void rotate(int &p,int d){
int tmp=ch[p][d^1];ch[p][d^1]=ch[tmp][d],ch[tmp][d]=p,p=tmp;
pushup(ch[p][d]),pushup(p);
}
void insert(int &p,int v){
if(!p){create(p,v);return;}
if(v==val[p]){cnt[p]++;pushup(p);return;}
int d=(v>val[p]);
insert(ch[p][d],v);
if(rk[p]<rk[ch[p][d]]) rotate(p,d^1);
pushup(p);
}
void remove(int &p,int v){
if(!p) return;
if(v==val[p]){
if(cnt[p]>1){cnt[p]--;pushup(p);return;}
if(ls||rs){
if(!rs||rk[ls]>rk[rs]) rotate(p,1),remove(rs,v);
else rotate(p,0),remove(ls,v);
pushup(p);
}else p=0;
return;
}
if(v<val[p]) remove(ls,v);
else remove(rs,v);
pushup(p);
}
int get_rk(int p,int v){
if(!p) return 1;
if(val[p]==v) return siz[ls]+1;
if(val[p]>v) return get_rk(ls,v);
return siz[ls]+cnt[p]+get_rk(rs,v);
}
int get_val(int p,int x){
if(!p) return inf;
if(siz[ls]>=x) return get_val(ls,x);
if(siz[ls]+cnt[p]>=x) return val[p];
return get_val(rs,x-siz[ls]-cnt[p]);
}
int get_pre(int p,int v){
int ans=0;
while(p){
if(val[p]<v) ans=val[p],p=rs;
else p=ls;
}
return ans;
}
int get_nxt(int p,int v){
int ans=inf;
while(p){
if(val[p]>v) ans=val[p],p=ls;
else p=rs;
}
return ans;
}
int main(){
build();
cin>>n;
while(n--){
int op,x;cin>>op>>x;
switch(op){
case 1:{insert(rt,x);break;}
case 2:{remove(rt,x);break;}
case 3:{cout<<get_rk(rt,x)-1<<"\n";break;}
case 4:{cout<<get_val(rt,x+1)<<"\n";break;}
case 5:{cout<<get_pre(rt,x)<<"\n";break;}
case 6:{cout<<get_nxt(rt,x)<<"\n";break;}
}
}
return 0;
}

浙公网安备 33010602011771号