非旋Treap入門講義
阿新 • • 發佈:2020-10-21
https://www.cnblogs.com/akakw1/p/9892156.html
下面程式中給每個點設定了一個隨機的優先順序,用於樹的合併時使用。
#include<bits/stdc++.h> using namespace std; inline int gi() { register int x=0,op=1,c; while(c=getchar(),c<'0'||c>'9')if(c=='-')op=-op; x=c^48; while(c=getchar(),c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48); return x*op; } struct node { int son[2]; int val, s; int v; node() { son[0] = son[1] = 0; s = 0; val = rand(); } }t[100001]; void push_up(int p) { t[p].s = t[t[p].son[0]].s + t[t[p].son[1]].s + 1; } void split_v(int p, int v, int &x, int &y) { if(!p)return void(x = y = 0); if(t[p].v>v) { y = p; split_v(t[p].son[0], v, x, t[p].son[0]); } else { x = p; split_v(t[p].son[1], v, t[p].son[1], y); } push_up(p); } void split_k(int p, int k, int &x, int &y) { if(!p)return void(x = y = 0); if(k <= t[t[p].son[0]].s) { y = p; split_k(t[p].son[0], k, x, t[p].son[0]); } else { x = p; split_k(t[p].son[1], k - t[t[p].son[0]].s - 1, t[p].son[1], y); } push_up(p); } int merge(int x, int y) { if(! x || ! y)return x + y; if(t[x].val < t[y].val) //每個點有個隨機優先順序 { t[x].son[1] = merge(t[x].son[1], y); //將y與x的右子樹合併,再做為x的右子樹 push_up(x); return x; } else { t[y].son[0] = merge(x, t[y].son[0]); // 將x與y的左子樹合併,再做為y的左子樹 push_up(y); return y; } } int tot=0; int new_node(int v) { t[++tot].v = v; t[tot].s=1; return tot; } int root=0; int main() { srand(time(0)); int n=gi(); int op,x; int r1,r2; while(n--) { op=gi(),x=gi(); switch(op) { case 1://插入 split_v(root,x,root,r1); root=merge(root,merge(new_node(x),r1)); break; case 2://刪除 split_v(root,x-1,root,r1); split_k(r1,1,r2,r1); root=merge(root,r1); break; case 3://排名 split_v(root,x-1,root,r1); printf("%d\n",t[root].s+1); root=merge(root,r1); break; case 4://k小值 split_k(root,x-1,root,r1); split_k(r1,1,r1,r2); printf("%d\n",t[r1].v); root=merge(root,merge(r1,r2)); break; case 5://前驅 split_v(root,x-1,root,r1); split_k(root,t[root].s-1,root,r2); printf("%d\n",t[r2].v); root=merge(root,merge(r2,r1)); break; case 6://後繼 split_v(root,x,root,r1); split_k(r1,1,r1,r2); printf("%d\n",t[r1].v); root=merge(root,merge(r1,r2)); } } return 0; }
當然這個隨機的優先順序也可以不設定,合併時隨機合併也可以
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef pair<int,int> pii; int tot,son[100005][2],c[100005],val[100005],root; int read() { int x=0,f=1; char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1; for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0'; return x*f; } int random(int lim) { return rand()%lim+1; } void updata(int a) { c[a]=c[son[a][0]]+1+c[son[a][1]]; } int getrank(int v) //查詢權值為v的數字的排名 { int res=0; for(int x=root;x;) { if(val[x]<v) //如果當前根結點小於v,則所有v及其左子樹均小於v { res+=c[son[x][0]]+1; x=son[x][1]; } else x=son[x][0]; } return res+1; } pii split(int a,int k) //從a這個樹中分出K個點來, //這k個點所組成的樹的樹根做為其左返回值,其它的結點所形成的樹做為右返回值 { if(c[a]==k) //如果a這個樹正好有k個結點,則直接返回a這個樹,右返回值為0 return make_pair(a,0); if(k==0) return make_pair(0,a);//左邊為空樹,右為原來a這個樹 pii tmp; if(c[son[a][0]]>=k)//如果左子樹結點個數大於等於k { tmp=split(son[a][0],k);//從左子樹中分離 son[a][0]=tmp.second;//a的左子樹只剩下了分離後的結點 updata(a);//更新a的相關值 return make_pair(tmp.first,a);//返回分離後的樹與從前a樹剩下的部分 } else { tmp=split(son[a][1],k-c[son[a][0]]-1);//減去左子樹及根結點 son[a][1]=tmp.first; updata(a); return make_pair(a,tmp.second); } } int merge(int a,int b) //將根結點編號分為a,b的樹進行合併 //此時b樹中所有點權值大於a樹中的所有點權 { if(!a||!b)return a+b; if(random(c[a]+c[b])<=c[a]) { son[a][1]=merge(son[a][1],b);//將b做為a的右子樹 updata(a); return a; } else { son[b][0]=merge(a,son[b][0]);//將a做為b的左子樹 updata(b); return b; } } void insert(int v) { tot++; val[tot]=v; memset(son[tot],0,sizeof(son[tot])); c[tot]=1; int x=getrank(v)-1; pii tmp=split(root,x); //從root中分離出前x個結點,tmp.first為分裂後左樹的根結點編號 //tmp.second為分裂後右根的根結點編號 root=merge(merge(tmp.first,tot),tmp.second); //先將第tot個點與分離出來的左樹合併,再與其右樹合併 return; } void del(int v) //刪除權值為v的數字 { int x=getrank(v); pii tmp=split(root,x); int c=tmp.second; tmp=split(tmp.first,x-1); root=merge(tmp.first,c); } int getval(int a,int k)//查詢第k小的數字 { if(!k)return 0; if(c[son[a][0]]>=k)return getval(son[a][0],k); if(c[son[a][0]]+1==k)return a; return getval(son[a][1],k-c[son[a][0]]-1); } int main() { srand(20020220); int n=read(); for(int i=1;i<=n;i++) { int mode=read(),x=read(); if(mode==1)insert(x); if(mode==2)del(x); if(mode==3)printf("%d\n",getrank(x)); if(mode==4)printf("%d\n",val[getval(root,x)]); if(mode==5)printf("%d\n",val[getval(root,getrank(x)-1)]); if(mode==6)printf("%d\n",val[getval(root,getrank(x+1))]); } return 0; }