1. 程式人生 > 其它 >P6136 【模板】普通平衡樹(資料加強版) 非旋轉treap演算法指標版

P6136 【模板】普通平衡樹(資料加強版) 非旋轉treap演算法指標版

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

//非旋轉的Treap樹 
#include<bits/stdc++.h>
using namespace std;
const int INF=0x7fffffff;
struct Node *nil; // 自定義的空指標,防止翻車(RE)
struct Node {
	Node *ch[2]; // 結點的左右孩子。為什麼不分開寫成lc,rc呢?往後就知道了
	int v, s, c; // v表示該結點的值,s表示以該結點為根的子樹大小,c表示權值v的結點數量(合併了相同權值的結點),即v的副本數量
	int r; // Treap專有的隨機數,是大根堆的關鍵字
	void maintain() { // 維護當前結點的資訊
		s = ch[0]->s + ch[1]->s + c;
	}
	Node(int v) : v(v), c(1), s(1), r(rand()) { ch[0] = ch[1] = nil; } // 新建結點
} *root;
void init() {
	srand(0); // 隨機數初始化
	nil = new Node(0); // 空指標初始化
	root = nil->ch[0] = nil->ch[1] = nil; // 左右孩子指向自身
	nil->s = nil->c = 0; // 防止空指標影響後面的操作
}
void split(Node *o, int v, Node* &l, Node* &r) {
	if (o == nil) { l = r = nil; return; } // 到了空結點兩邊附上空後結束
	if (o->v < v) { l = o; split(o->ch[1], v, l->ch[1], r); l->maintain(); } // 第一種情況。注意分裂後要及時維護資訊
	else { r = o; split(o->ch[0], v, l, r->ch[0]); r->maintain(); } // 第二種情況。同上
}
Node* merge(Node *a, Node *b) {
	if (a == nil) return b; // 如果a空返回b
	if (b == nil) return a; // 如果b空返回a
	if (a->r > b->r) { a->ch[1] = merge(a->ch[1], b); a->maintain(); return a; } // 比較兩者的隨機關鍵字,大的先合併
	else { b->ch[0] = merge(a, b->ch[0]); b->maintain(); return b; }
}
void insert(Node* &rt, int v) {
	Node *l, *r;
	split(rt, v, l, r);
	rt = merge(merge(l, new Node(v)), r);
}
void remove(Node* &rt, int v) {
	Node *l, *mid, *r;
	split(rt, v, l, r);
	split(r, v+1, mid, r);
	rt = merge(merge(l, merge(mid->ch[0], mid->ch[1])), r);
	delete mid;
}
//v的排名 
int get_rank(Node* o, int v) {
	/*
	        10
	        /\
		   4
		   \
		   10
		   /\
		  7
		 /\
		.. 10 	 
	有錯 
	if (v < o->v) return get_rank(o->ch[0], v); // v在左子樹中
	if (o->ch[0]&&o->ch[0]->v==v) return get_rank(o->ch[0],v);
	if (o->v== v) return o->ch[0]->s + 1; // 找到v
	return get_rank(o->ch[1], v) + o->ch[0]->s + o->c;
	// v在右子樹中,此時要將左子樹中的所有元素以及根的元素數統計起來
	*/
	/*
	int ans=0;
	while(o!=nil)
	{
		if (o->v>=v)
		{
			o=o->ch[0];	
		}
		else
		{
			ans+=o->ch[0]->s+1;
			o=o->ch[1];
		}
	}
	return ans+1;	
	*/
	if (o==nil) return 1;
	if (o->v>=v) return get_rank(o->ch[0],v);
	else return o->ch[0]->s+1+get_rank(o->ch[1],v);
}
//第k小數 
int get_val(Node* o, int k) {
	if (k <= o->ch[0]->s) return get_val(o->ch[0], k); // 排名為k的數在左子樹中
	else if (k == o->ch[0]->s + o->c) return o->v; // 為o
	else return get_val(o->ch[1], k - o->ch[0]->s - o->c); // 在右子樹中
}
int get_pre(Node *o, int v) { // 查前驅
	if (o == nil) return -INF; // 找到空結點返回無窮小目的是不干擾其它解
	if (o->v >= v) return get_pre(o->ch[0], v); // v大於當前結點o的值,向左走找小一點的值
	return max(o->v, get_pre(o->ch[1], v)); // 否則向右走找更大的值並與當前值比較
	/*
	有點慢 
	if (o == nil) return -INF; // 找到空結點返回無窮小目的是不干擾其它解
	return get_val(o,get_rank(o,v)-1);	
	*/
}
int get_next(Node *o, int v) { // 查後繼,與上面完全相反
	/*
	if (o == nil) return INF;
	if (o->v <= v) return get_next(o->ch[1], v);
	return min(o->v, get_next(o->ch[0], v));
	*/
	return get_val(o,get_rank(o,v+1));//有點慢 
}
int main()
{
	int n,m,op,x,last=0,ans=0;
	init();
	scanf("%d %d",&n,&m);
	while(n--)
	{
		scanf("%d",&x);
		insert(root,x);
	}
	while(m--)
	{
		scanf("%d %d",&op,&x);
		x=last^x;
		if (op==1) 
		   insert(root,x);
		else if(op==2) 
		   remove(root,x);
		else if(op==3) 
		{
			last=get_rank(root,x);
			ans^=last;
		}
		else if(op==4)
		{
			last=get_val(root,x);
			ans^=last;
		} 
		else if(op==5)
		{
			last=get_pre(root,x);
			ans^=last;
		} 
		else if(op==6) 
		{
			last=get_next(root,x);
			ans^=last;
		}
	}
	cout<<ans<<endl;
}