fhq-treap学习笔记
本文内容粗略,不适合新手阅读
但如果你已经进来了,推荐你到这里学习
当然是写给我复习用
fhq-treap通过分裂和合并连个操作,以临界值分离二叉搜索树
由于在合并时引进可了随机数,使其平衡性得到保障
结构体
struct node{
int ls,rs,val,p,s;
//分别为左儿子,右儿子,该节点存的值,随机数(用于合并),以该节点为根的子树的大小
};
分离
void split(int u,int x,int& l,int& r){//u当前节点,x临界值,l在值域为1到x之间的树接下来需要添加节点的位置,r与l同理,值域在x+1到m之间
if(u==0){//如果u节点时不存在的,这里不需要添加,l和r指向0,以该节点为根的子树大小
l=r=0;
return;
}
if(t[u].val<=x){//当前节点的值比x小,因为以其左节点为根的子树的值均小于该节点的值,所以将左子树和当前节点给l,右子树继续分离
l=u;
split(t[u].rs,x,t[u].rs,r);
}
else{//与上同理
r=u;
split(t[u].ls,x,l,t[u].ls);
}
push_up(u);//更新节点大小
}
合并
合并时,并不能确定哪个点作为根,如果只选左或只选右或诸如此类有规律性的选法,很有可能使平衡树退化
所以引入随机数,随机数p值较大的优先作为根节点
//调用merge的条件:u点的val小于等于v点的val
int merge(int u,int v){//返回merge后的根节点
if(!u||!v) return u|v;
if(t[u].p>t[v].p){//u为根节点
t[u].rs=merge(t[u].rs,v);//注意顺序
push_up(u);
return u;
}
else{//v为根节点
t[v].ls=merge(u,t[v].ls);//注意顺序
push_up(v);
return v;
}
}
模板
然后就可以通过merge和split进行各种操作了
过程中维护一个根节点即可
放个我自己写的模板
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e5+5;
void read(int& x){
char c;
bool f=0;
while((c=getchar())<48) f|=(c==45);
x=c-48;
while((c=getchar())>47) x=x*10+c-48;
x=(f ? -x : x);
return;
}
mt19937 rd(time(NULL));
struct node{
int ls,rs,val,p,s;
};
int node_cnt=0,rt;
node t[maxn];
int new_node(int x){
++node_cnt;
t[node_cnt]=(node){0,0,x,(int)rd(),1};
return node_cnt;
}
void push_up(int u){
t[u].s=t[t[u].ls].s+t[t[u].rs].s+1;
}
void split(int u,int x,int& l,int& r){
if(u==0){
l=r=0;
return;
}
if(t[u].val<=x){
l=u;
split(t[u].rs,x,t[u].rs,r);
}
else{
r=u;
split(t[u].ls,x,l,t[u].ls);
}
push_up(u);
}
int merge(int u,int v){
if(!u||!v) return u|v;
if(t[u].p>t[v].p){
t[u].rs=merge(t[u].rs,v);
push_up(u);
return u;
}
else{
t[v].ls=merge(u,t[v].ls);
push_up(v);
return v;
}
}
void insert(int x){
int u,v;
split(rt,x,u,v);
int p=new_node(x);
rt=merge(merge(u,p),v);
}
void remove(int x){
int u,v,w;
split(rt,x,u,v);
split(u,x-1,u,w);
w=merge(t[w].ls,t[w].rs);
rt=merge(merge(u,w),v);
}
int rnk(int x){
int u,v;
split(rt,x-1,u,v);
int ans=t[u].s+1;
rt=merge(u,v);
return ans;
}
int kth(int x,int u=rt){
int i=t[t[u].ls].s+1;
if(i==x) return t[u].val;
else if(x<i) return kth(x,t[u].ls);
else return kth(x-i,t[u].rs);
}
int pre(int x){
int u,v;
split(rt,x-1,u,v);
int ans=kth(t[u].s,u);
rt=merge(u,v);
return ans;
}
int nxt(int x){
int u,v;
split(rt,x,u,v);
int ans=kth(1,v);
rt=merge(u,v);
return ans;
}
int q;
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
read(q);
int op,x;
while(q--){
read(op),read(x);
if(op==1) insert(x);
else if(op==2) remove(x);
else if(op==3) printf("%d\n",rnk(x));
else if(op==4) printf("%d\n",kth(x));
else if(op==5) printf("%d\n",pre(x));
else printf("%d\n",nxt(x));
}
return 0;
}
//^o^

浙公网安备 33010602011771号