Loading

【题解】P6136 【模板】普通平衡树(数据加强版)

来自刚刚学会Treap的蒟蒻

题目链接:

特别不习惯用一堆数组,结构体多香啊

struct node{
	int son[2];//son[
	int size,cnt;
	int val,rd;
}trp[1500000];
int tot,root;

其实完整代码里都有~
只不过无聊,单独拿出来~

int rrand(void){
    return seed=(int)((long long)(seed)*974485642LL%21474836LL);
    /*手写rand()取随机数*/
}
#include<bits/stdc++.h>
#define re register
#define rd(x) x=read()
struct node{
	int son[2];//son[0]左儿子,son[1]右儿子 
	int size,cnt;
	//因为treap不希望出现值相同的节点,(想想为什么) 
	//所以用cnt统计相同的值 
	int val,rd;
	//rd 是随机的权值,整个树按照这个打乱 
	//当然,rd也可以被称为该节点的优先级 
}trp[1500000];
int tot,root;
int seed=5201314;
int rrand(void){
    return seed=(int)((long long)(seed)*974485642LL%21474836LL);
    /*手写rand()取随机数*/
}

void newnode(int &now,int val){
	/* 
	val = val
	size = 1
	cnt = 1;
	rd rand()
	*/
	/*基础的新建节点,没毛病*/ 
	now = ++tot;
	trp[now].val = val;
	trp[now].size = trp[now].cnt = 1;
	trp[now].rd = rrand();
	/*这里吐槽下,treap真的是看脸的算法啊*/
}
void update(int now){
	/*更新新节点,很简单,这里没啥问题 */
	trp[now].size = trp[trp[now].son[0]].size+trp[trp[now].son[1]].size+trp[now].cnt;
}
void rotate(int &now,int d){
	/*
	自闭了十分钟的旋转操作,
	位运算理解成左右儿子切换或者左右方向切换就好。 
	*/
	int son = trp[now].son[d^1];
	trp[now].son[d^1] = trp[son].son[d];
	trp[son].son[d] = now;
	now = son;
	/*注意,从下到上更新,先更新旋转后节点的d儿子,最后更新旋转的now节点*/ 
	update(trp[now].son[d]);
	update(now);
}
void insert(int &now,int val){
	if(!now){
		newnode(now,val);//终于可以插入新节点了 
		return;
	}//在那之前,我们需要找到在何处插
	++trp[now].size;
	if(trp[now].val==val){
		trp[now].cnt++;//前面提到的计数器,相同的值直接统计数量就好
		update(now);//我还在思考这里要不要update一下 
		return;
	}
	if(trp[now].val>val){
		insert(trp[now].son[0],val);
		if(trp[now].rd<trp[trp[now].son[0]].rd)
			rotate(now,1);
	}//左右分头,记住一点,这棵树中,越往上rd越大,所以我们if比较里的内容其实很简单
	//如果遇到儿子的rd比父辈大的时候,我们就旋转一下 
	else{
		insert(trp[now].son[1],val);
		if(trp[now].rd<trp[trp[now].son[1]].rd)
			rotate(now,0);
	}
	update(now);
}
void del(int &now,int val){
	if(!now)return;//都没节点了,你删个锤子,可以加返回值判断是否删成功 
	++trp[now].size;
	if(trp[now].val==val){
		if(trp[now].cnt>1){
			trp[now].cnt--;
			update(now);
			return;
		}
		if(trp[now].son[0]||trp[now].son[1]){
			if(!trp[now].son[1]||trp[trp[now].son[0]].rd>trp[trp[now].son[1]].rd)
				rotate(now,1),del(trp[now].son[1],val);
			else
				rotate(now,0),del(trp[now].son[0],val);
		}//删除这段其实用手画三四张模拟就懂了 
		else now = 0;
	}//蒟蒻的我可能会在B站录个视频什么的 
	else if(trp[now].val>val) 
		del(trp[now].son[0],val);
	else del(trp[now].son[1],val);
	update(now);
}
int find_rank(int now,int val){
	if(!now)
		return INT_MIN;
	if(trp[now].val==val)
		return trp[trp[now].son[0]].size+1;
	else if(trp[now].val>val)
		return find_rank(trp[now].son[0],val);
	else
		return trp[trp[now].son[0]].size + trp[now].cnt + find_rank(trp[now].son[1],val);
}
int find_val(int now,int rank){
	if(!now)
		return INT_MAX;
	if(trp[trp[now].son[0]].size>=rank)
		return find_val(trp[now].son[0],rank);
	else if(trp[trp[now].son[0]].size+trp[now].cnt>=rank)
		return trp[now].val;
	else
		return find_val(trp[now].son[1],rank-trp[trp[now].son[0]].size-trp[now].cnt);
}
int find_pre(int val){
	re int now = root,pre = 0;
	while(now){
		if(trp[now].val<val)
			pre = trp[now].val,now = trp[now].son[1];
		else
			now = trp[now].son[0];
	}
	return pre;
}
int find_nex(int val){
	re int now = root,nex = 0;
	while(now){
		if(trp[now].val>val)
			nex = trp[now].val,now = trp[now].son[0];
		else
			now = trp[now].son[1];
	}
	return nex;
}
inline int read(){
	re int ans = 0;
	re bool f = 1;
	re char ch = getchar();
	while(ch<'0'||ch>'9')ch=='-'?f=0,ch=getchar():ch=getchar();
	while(ch>='0'&&ch<='9')ans =(ans<<3)+(ans<<1)+(ch^48),ch = getchar(); 
	return f?ans:-ans;
} 
signed main(void){
	int n,m,last = 0,ans = 0,ooo;
	n = read();m = read();++n;++m;
	while(--n){
		ooo = read();
		insert(root,ooo);
	}
	while(--m){
		int opt,x;
		opt = read();
		x = read();
		switch(opt){
			case 1:
				insert(root,x^last);
				break;
			case 2:
				del(root,x^last);
				break;
			case 3:
				ans ^= (last = find_rank(root,x^last));
				break;
			case 4:
				ans ^= (last = find_val(root,x^last));
				break;
			case 5:
				ans ^= (last = find_pre(x^last));
				break;
			case 6:
				ans ^= (last = find_nex(x^last));
				break;			
		}
	}
	printf("%d",ans);
	return 0;
}

感谢观看,如有不懂欢迎评论,博主全年365天无休,24小时内必回

嘿嘿,点个关注推荐呗~

posted @ 2020-03-31 22:45  HistoneMax  阅读(57)  评论(0编辑  收藏  举报