FHQ-Treap的奇妙WA 悬赏
查看原帖
FHQ-Treap的奇妙WA 悬赏
258178
Benzenesir楼主2022/8/30 12:16

是这样的,我自己测试样例,发现有时候能输出正确,有时候答案是错的,有时候在 5 8 这里就不动了,求dalao赐教

#include <iostream>
#include <queue>
#include <time.h>
#include <string.h>

using namespace std;
const int maxN=2*1e6+10;
int n,m; int r1=0,r2=0,r3=0;
int son[maxN][2],fa[maxN],size[maxN],val[maxN],data[maxN],root,idx;
int rd[maxN];
queue<int> rb;

inline void update(int x){
	if(x==0) return ;
	size[x]=size[son[x][1]]+size[son[x][0]]+1;
	//cout << x << endl;
	//cout << size[son[x][1]] << " " << size[son[x][0]] << endl;
}

inline void split(int now,int k,int &x,int &y){//按权值分裂,小于等于k的分到左子树,大于的分到右子树 
	if(!now){
		x=y=0; 
	}
	else{
		if(data[now]<=k){
			x=now;
			split(son[now][1],k,son[now][1],y);//这里我们已经把x更新为now了,由于treap的结构坚不可摧,所以右子树都是大于now的,所以再合并时就把其合并到now的右儿子上 
		}
		else{
			y=now;
			split(son[now][0],k,x,son[now][0]);
		}
	}
	update(now);
}

inline int merge(int a,int b){
	if(!a||!b) return a+b;
	if(val[a]<val[b]){
		son[a][1]=merge(son[a][1],b);//将右子树和b合并,作为a的新右子树 
		update(a);
		return a;
	}
	else{
		son[b][0]=merge(a,son[b][0]);//同理 
		update(b);
		return b;
	}
}

inline int new_point(int v){
	int p;
	if(!rb.empty()) {
		p=rb.front();
		rb.pop();
	}
	else p=++idx;
	size[p]=1;
	val[p]=rand();
	while(rd[val[p]]) val[p]=rand();
	rd[val[p]]=1;
	data[p]=v;
	//cout << size[p] << " " << val[p] << " " << data[p] << endl;
	return p;
}

inline void insert(int x){
	int r1,r2;
	split(root,x,r1,r2);
	root=merge(merge(r1,new_point(x)),r2);
}

inline void del(int x){//就算x不在bst里面,我们也能通过split找到它 
	int r1,r2,r3;
	split(root,x,r1,r2);
	split(r1,x-1,r1,r3);
	rb.push(r3); 
	r3=merge(son[r3][0],son[r3][1]);
	root=merge(merge(r1,r3),r2);
}

inline int inrank(int x){
	int r1,r2;
	int ans;
	split(root,x-1,r1,r2);
	ans=size[r1]+1;
	root=merge(r1,r2);
	return ans;
}

inline int kth(int k){
	int now=root;
	while(1){
		if(size[son[now][0]]<k&&size[son[now][0]]+1>=k){
			return data[now];
		}
		if(size[son[now][0]]>=k){
			now=son[now][0];
		}
		else{
			k-=size[son[now][0]]+1,now=son[now][1];
		}
	}
}

inline int pre(int x){
	return kth(inrank(x)-1);
}
inline int suffix(int x){
	return kth(inrank(x+1));//这里我们将值加一,其排名一定是最小的严格大于x的数的排名 
}

signed main(){
	//freopen("P6136_1.in","r",stdin);
	//freopen("FHQ.out","w",stdout);
	//memset(size,0,sizeof(size));
	srand(time(0));
	ios::sync_with_stdio(false);//cin加速 
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);//再度加速 
	//不能用printf,scanf
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		int x;cin >> x;
		insert(x);
	//	cout << size[root] << endl;
	}
	int last=0,ans;
	//del(4);
	//insert(9);
	//cout << inrank(10) << endl;
	
	while(m--){
		//cout << data[root] << endl;
		int opt,x;
		cin >> opt >> x;
		x^=last;
		//cout << x << endl;
		switch (opt){
			case 1:
				insert(x);
				break;
			case 2:
				del(x);
				break;
			case 3:
				last=inrank(x);
			//	cout << last << endl;
				ans^=last;
				break;
			case 4:
				last=kth(x);
			//	cout << last << endl;
				ans^=last;
				break;		
			case 5:
				last=pre(x);
				//cout << inrank(x) << endl;
				//cout << last << endl;
				ans^=last;
				break;
			case 6:
				last=suffix(x);
			//	cout << last << endl;
				ans^=last;
				break;	
		}
	}
	cout << ans << endl;
	
	
	return 114514-114514;
}
/*
treap中,由于随机值的存在,所以bst中的每一个节点只代表一个数,相同的数会被分配到不同的节点中,不像splay需要维护cnt 
*/
2022/8/30 12:16
加载中...