1. 程式人生 > >種下一棵樹:有旋Treap

種下一棵樹:有旋Treap

調整 同時 我們 ++ log int 隨機函數 for rtu

第一個平衡樹板子,有旋Treap。用隨機函數規定一個堆,維護點權的同時維護堆的性質,可以有效地避免退化成鏈。按我的理解,建立一棵二叉排序樹,樹的形態會和給出節點的順序有關。按照出題人很機智定理,數據肯定不會太容易操作,這時候就需要我們自行調整“數據順序”,平衡樹應運而生。

這個板子涵蓋的操作有左旋、右旋(維護堆性質)、添加節點、刪除節點(建樹相關)、查找第x個元素、查找元素排名、查找前驅、查找後繼這8種操作。改變樹本身的操作都是取地址傳參的,詢問操作則都是簡單傳參。原理不是太難理解,應用則看以後刷題了。

#include<iostream>
#include
<cstdio> #include<cstring> #include<ctime> #include<cstdlib> using namespace std; const int sj=100010; int n,opt,g,jg,cs,size; struct tree { int l,r,v,w,rnd,size; }t[sj]; void update(int x) { t[x].size=t[t[x].l].size+t[t[x].r].size+t[x].w; } void lturn(int &x) {
int tt=t[x].r; t[x].r=t[tt].l; t[tt].l=x; t[tt].size=t[x].size; update(x); x=tt; } void rturn(int &x) { int tt=t[x].l; t[x].l=t[tt].r; t[tt].r=x; t[tt].size=t[x].size; update(x); x=tt; } void cr(int &x,int y) { if(x==0) { size
++; x=size; t[x].size=t[x].w=1; t[x].v=y; t[x].rnd=rand(); return; } t[x].size++; if(t[x].v==y) t[x].w++; else if(y>t[x].v) { cr(t[x].r,y); if(t[t[x].r].rnd<t[x].rnd) lturn(x); } else { cr(t[x].l,y); if(t[t[x].l].rnd<t[x].rnd) rturn(x); } } void sc(int &k,int x) { if(k==0) return; if(t[k].v==x) { if(t[k].w>1) { t[k].w--; t[k].size--; return; } if(t[k].l*t[k].r==0) k=t[k].l+t[k].r; else if(t[t[k].l].rnd<t[t[k].r].rnd) rturn(k),sc(k,x); else lturn(k),sc(k,x); } else if(x>t[k].v) t[k].size--,sc(t[k].r,x); else t[k].size--,sc(t[k].l,x); } int query_rank(int k,int x) { if(k==0) return 0; if(t[k].v==x) return t[t[k].l].size+1; else if(x>t[k].v) return t[t[k].l].size+t[k].w+query_rank(t[k].r,x); else return query_rank(t[k].l,x); } int query_num(int k,int x) { if(k==0) return 0; if(x<=t[t[k].l].size) return query_num(t[k].l,x); else if(x>t[t[k].l].size+t[k].w) return query_num(t[k].r,x-t[t[k].l].size-t[k].w); else return t[k].v; } void query_pre(int k,int x) { if(k==0) return; if(t[k].v<x) jg=k,query_pre(t[k].r,x); else query_pre(t[k].l,x); } void query_sub(int k,int x) { if(k==0) return; if(t[k].v>x) jg=k,query_sub(t[k].l,x); else query_sub(t[k].r,x); } int main() { //freopen("t.txt","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&opt,&cs); if(opt==1) cr(g,cs); if(opt==2) sc(g,cs); if(opt==3) printf("%d\n",query_rank(g,cs)); if(opt==4) printf("%d\n",query_num(g,cs)); if(opt==5) { jg=0; query_pre(g,cs); printf("%d\n",t[jg].v); } if(opt==6) { jg=0; query_sub(g,cs); printf("%d\n",t[jg].v); } } //while(1); return 0; }

種下一棵樹:有旋Treap