【模板】普通平衡樹(資料加強版)
阿新 • • 發佈:2022-04-09
學習的一種新的平衡樹。主要是學到可持久化這個部分,可持久化平衡樹似乎用非旋Treap來寫會簡便一些,就來了。其實這種平衡樹很好理解,但由於種種腦殘原因我還是寫了一個半小時……
這種樹思想就是考慮分裂和合並平衡樹達到平衡的目的,為了平衡需要用Treap的思想,給每個節點賦值一個優先順序,merge的時候按優先順序合併就可以保證複雜度。分裂部分也挺好理解,以最常用的按值分裂來說,分裂過程就是首先判斷樹根在哪棵半樹裡,然後判斷出了樹根之後就有一半的節點有了歸宿,接下來要做的就是遞迴下去分裂即可。合併部分寫起來很像左偏樹,只不過按優先順序合併。其它的如插入刪除操作都是基於分裂又合併的,複雜度還好,跑起來比我寫的Splay慢了一點,但可以接受。
程式碼:
#include<cstdio> #include<ctime> #include<cstdlib> //#define zczc using namespace std; const int N=1100010; inline void read(int &wh){ wh=0;int f=1;char w=getchar(); while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();} while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();} wh*=f;return; } int m,n,cnt,root; #define lc t[x].l #define rc t[x].r struct node{ int l,r,data,size,p; }t[N]; inline int newone(int val){ t[++cnt]=(node){0,0,val,1,rand()};return cnt; } inline void pushup(int x){ t[x].size=t[lc].size+t[rc].size+1; } inline void split(int x,int val,int &a,int &b){ if(!x){a=b=0;return;} if(t[x].data<=val){a=x;split(rc,val,rc,b);} else{b=x;split(lc,val,a,lc);}pushup(x); } inline int merge(int x,int y){ if(!x||!y)return x+y; if(t[x].p<t[y].p){rc=merge(rc,y);pushup(x);return x;} else{t[y].l=merge(x,t[y].l);pushup(y);return y;} } inline void insert(int val){ int a,b;split(root,val,a,b); root=merge(merge(a,newone(val)),b); } inline void delet(int val){ int a,b,c; split(root,val,a,c); split(a,val-1,a,b); b=merge(t[b].l,t[b].r); root=merge(merge(a,b),c); } int tot; inline int get(int x,int val){ if(t[lc].size+1==val)return t[x].data; if(t[lc].size>=val)return get(lc,val); else return get(rc,val-t[lc].size-1); } inline int get_min(int val){ int a,b;split(root,val,a,b); int re=get(b,1); root=merge(a,b);return re; } inline int get_max(int val){ int a,b;split(root,val-1,a,b); int re=get(a,t[a].size); root=merge(a,b);return re; } inline int get_rank(int val){ int a,b;split(root,val-1,a,b); int re=t[a].size+1; root=merge(a,b);return re; } #undef lc #undef rc signed main(){ #ifdef zczc freopen("in.txt","r",stdin); #endif srand(time(0)); int op,lan=0,in,ans=0; read(m);read(n); for(int i=1;i<=m;i++){read(in);insert(in);} for(int i=1;i<=n;i++){ read(op);read(in);in^=lan; if(op==1)insert(in); else if(op==2)delet(in); else if(op==3)ans^=(lan=get_rank(in)); else if(op==4)ans^=(lan=get(root,in)); else if(op==5)ans^=(lan=get_max(in)); else if(op==6)ans^=(lan=get_min(in)); } printf("%d\n",ans); return 0; }