1. 程式人生 > 其它 >[模板]普通平衡樹-無旋Treap(FHQ Treap)

[模板]普通平衡樹-無旋Treap(FHQ Treap)

//非旋Treap(FHQ Treap)
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#define WR WinterRain
using namespace std;
const int WR=1001000;
struct FHQ_Treap{
    int ch[2],val,rnk,sze;
    FHQ_Treap(){ch[0]=ch[1]=val=rnk=sze=0;}
}tree[WR];
int n,root,tot;
int x,y,z;
int read(){
    
int s=0,w=1; char ch=getchar(); while(ch>'9'||ch<'0'){ if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=(s<<1)+(s<<3)+ch-48; ch=getchar(); } return s*w;//?????沒加*w????? } void pushup(int k){//這裡貌似不需要記錄副本數了 tree[k].sze=tree[tree[k].ch[0
]].sze+tree[tree[k].ch[1]].sze+1; } int add_point(int v){ tree[++tot].sze=1; tree[tot].val=v; tree[tot].rnk=rand();//但別的還是差不多的 return tot; } int treap_merge(int x,int y){//平衡樹合併 if(!x||!y) return x+y;//酷似線段樹合併 if(tree[x].rnk<tree[y].rnk){//如果x號節點比y號節點排名小 tree[x].ch[1]=treap_merge(tree[x].ch[1
],y);//把y合併到x的右子樹上 pushup(x); return x; }else{ tree[y].ch[0]=treap_merge(x,tree[y].ch[0]);//否則把x合併到y的左子樹上 pushup(y); return y; } } void treap_split(int pos,int v,int &x,int &y){ if(!pos) x=y=0;//分裂操作,把值小於v的和大於v的劈開 else{ if(tree[pos].val<=v){ //假如一個點的權值小於k //那麼它的所有左子樹都要分到左邊的樹裡,然後遍歷它的右兒子。 x=pos; treap_split(tree[pos].ch[1],v,tree[pos].ch[1],y); }else{ //假如一個點的權值大於k //那麼它的所有右子樹都要分到右邊的樹裡,然後遍歷它的左兒子。 y=pos; treap_split(tree[pos].ch[0],v,x,tree[pos].ch[0]); } pushup(pos); } } int get_num(int id,int v){//這裡返回的是樹的節點編號,不是節點值 while(1==1){ if(v<=tree[tree[id].ch[0]].sze){//如果比當前排名小去左子樹找 id=tree[id].ch[0]; }else if(v==tree[tree[id].ch[0]].sze+1){//如果就是當前節點返回 return id; }else{ v-=tree[tree[id].ch[0]].sze+1;//否則去右子樹找 id=tree[id].ch[1]; } } } int main(){ n=read();root=0; for(int i=1;i<=n;i++){ int opt=read(),v=read(); if(opt==1){//insert //插入一個權值為v的點,把樹按照v的權值split成兩個,再按照順序merge回去 treap_split(root,v,x,y); root=treap_merge(treap_merge(x,add_point(v)),y); } if(opt==2){//delete //刪除權值為v的點,把樹按照v分成兩個a,b, //再把a按照v-1分成c,d。 //把c的兩個子兒子merge起來,再merge(merge(c,d),b) treap_split(root,v,x,z); treap_split(x,v-1,x,y); y=treap_merge(tree[y].ch[0],tree[y].ch[1]); root=treap_merge(treap_merge(x,y),z); } if(opt==3){//get_rank //把root按v-1 split成x,y,排名是x的siz treap_split(root,v-1,x,y); printf("%d\n",tree[x].sze+1); root=treap_merge(x,y); } if(opt==4){ printf("%d\n",tree[get_num(root,v)].val); } if(opt==5){ //找前驅的話把root按v-1 split成x,y,在x裡面找最大值 treap_split(root,v-1,x,y); printf("%d\n",tree[get_num(x,tree[x].sze)].val); root=treap_merge(x,y); } if(opt==6){ //找後繼的話把root按v split成x,y,在y裡找最小值 treap_split(root,v,x,y); printf("%d\n",tree[get_num(y,1)].val); root=treap_merge(x,y); } } return 0; }