1. 程式人生 > 其它 >【模板】普通平衡樹(資料加強版)

【模板】普通平衡樹(資料加強版)

link

學習的一種新的平衡樹。主要是學到可持久化這個部分,可持久化平衡樹似乎用非旋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;
}