2020 牛客 NOIP 赛前集训营 提高级(第四场) 平衡树模板

B-色球

【题目描述】
牛牛有\(n\)种颜色的彩色小球(编号\(1\)\(n\)),每种颜色的小球他都有无限多个。他
还有\(n\)个球桶(编号\(1\)\(n\)),球桶的内径与小球直径相当且高度是无限大的,因
此能容纳无限多的小球。他想用这些小球和球桶玩游戏。
一开始这些球桶都是空的,紧接着他会顺次地做\(m\)个操作,每个操作都是以下 \(3\)
类操作中的一个。

  1. \(x\)个颜色为\(y\)的彩色小球放到第\(z\)个桶的最上面(\(push\) \(x\) \(y\) \(z\)) ;
  2. 把最上面的\(x\)个小球从第 \(z\) 个桶内拿出来(\(pop\) \(x\) \(z\)) ;
  3. 把第\(u\)个桶的所有小球依次从顶部拿出放入第\(v\)个桶内(\(put\) \(u\) \(v\)) 。
    现在他已经确定好了这\(m\)个操作,但在他开始玩之前,他想知道每次他进行第二
    类操作取出的最后一个小球是什么颜色。

平衡树模板

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=202000;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while('0'<=ch&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,m,root[N*20],tot;
struct fhq_treap{
	int ls,rs,col,key,rev;
	ll sz,num;
}tr[N*20];
inline int newnode(int col,ll num){
	++tot;
	tr[tot].key=rand()*rand();
	tr[tot].col=col,tr[tot].sz=tr[tot].num=num;
	tr[tot].ls=tr[tot].rs=0;
	tr[tot].rev=0;
	return tot;
}
inline void pushup(int rt){
	tr[rt].sz=tr[rt].num;
	if(tr[rt].ls)tr[rt].sz+=tr[tr[rt].ls].sz;
	if(tr[rt].rs)tr[rt].sz+=tr[tr[rt].rs].sz;
//	tr[rt].sz=tr[tr[rt].ls].sz+tr[tr[rt].rs].sz+tr[rt].num;
}
inline void pushdown(int rt){
	if(tr[rt].rev){
		int l=tr[rt].ls,r=tr[rt].rs;
		if(l)tr[l].rev^=1,swap(tr[l].ls,tr[l].rs);
		if(r)tr[r].rev^=1,swap(tr[r].ls,tr[r].rs);
		tr[rt].rev=0;
	}
}
int merge(int x,int y){
	if((!x)||(!y))return x|y;
	pushdown(x),pushdown(y);
	int rt;
	if(tr[x].key<tr[y].key){
		rt=x;
		tr[rt].rs=merge(tr[x].rs,y);
	}
	else{
		rt=y;
		tr[rt].ls=merge(x,tr[y].ls);
	}
	pushup(rt);
	return rt;
}
//void split(int rt,int &x,int &y,ll k){
//	if(!rt){
//		x=y=0;
//		return;
//	} 
//	pushdown(rt);
//	if(tr[tr[rt].ls].sz+tr[rt].num>=k&&tr[tr[rt].ls].sz<k){
//		x=newnode(tr[rt].col,k);
//		y=newnode(tr[rt].col,tr[tr[rt].ls].sz+tr[rt].num-k);
//		tr[x].ls=tr[rt].ls;
//		tr[y].rs=tr[rt].rs;
//		tr[x].key=tr[y].key=tr[rt].key;
//		pushup(x),pushup(y);//一分为二,可能有num为0的点 
//		return;
//	}
//	if(tr[tr[rt].ls].sz>=k){
//		y=rt;
//		split(tr[rt].ls,x,tr[y].ls,k);
//	}
//	else{
//		x=rt;
//		split(tr[rt].rs,tr[x].rs,y,k-tr[tr[rt].ls].sz-tr[rt].num);
//	}
//	pushup(x),pushup(y);
//}
void print(int rt){
	if(!rt)return;
	pushdown(rt);
	print(tr[rt].ls);
	printf("col=%d num=%lld sz=%lld key=%d\n",tr[rt].col,tr[rt].num,tr[rt].sz,tr[rt].key);
	print(tr[rt].rs);
}
//void delete_0(int rt){
//	pushdown(rt);
//	if(tr[rt].num==1){
//		printf("%d\n",tr[rt].col);
//		return;
//	}
//	if(tr[tr[rt].ls].sz==1)delete_0(tr[rt].ls);
//	else delete_0(tr[rt].rs);
//}
//void solve(int x,int y){
//	ll sum=tr[root[x]].sz;
//	int a=0,b=0,c=0,d=0;
//	split(root[x],a,b,sum-y);
//	split(b,d,c,1);
//	if(tr[d].sz==1)
//	delete_0(d);
//	else{
//		exit(0);
//	}
//	root[x]=a;
//}

//自己写的二分裂终究还是挂了555 


void split(int rt,ll k,int &x,int &y,int &z){
	if(!rt){
		x=y=z=0;
		return;
	}
	pushdown(rt);
	if(tr[tr[rt].rs].sz>=k){
		x=rt;
		split(tr[rt].rs,k,tr[rt].rs,y,z);
	}
	else if(tr[tr[rt].rs].sz+tr[rt].num<k){
		z=rt;
		split(tr[rt].ls,k-tr[tr[rt].rs].sz-tr[rt].num,x,y,tr[rt].ls);
	}
	else{
		x=tr[rt].ls,z=tr[rt].rs;
		y=rt;
		tr[rt].ls=tr[rt].rs=0;
	}
	pushup(rt);
}//三分裂 
void solve(int x,int k){
	int a,b,c;
	split(root[x],k,a,b,c);
	root[x]=merge(a,newnode(tr[b].col,tr[c].sz+tr[b].num-k));
	printf("%d\n",tr[b].col);
}
int main(){
	char s[10];
//	freopen("5.in","r",stdin); 
//	freopen("color.in","r",stdin);
//	freopen("color.out","w",stdout);
	n=read(),m=read();
	for(int cas=1;cas<=m;++cas){
		scanf("%s",s);
		int x,y,z;
		if(s[2]=='s'){//push
			x=read(),y=read(),z=read();  
			root[z]=merge(root[z],newnode(y,x));
		}
		else if(s[2]=='t'){//put
			x=read(),y=read();
			tr[root[x]].rev^=1;
			swap(tr[root[x]].ls,tr[root[x]].rs);
			root[y]=merge(root[y],root[x]);
			root[x]=0;
		}
		else{//pop
			x=read(),y=read();
			solve(y,x);
		}
		tr[0].ls=tr[0].rs=tr[0].key=tr[0].num=tr[0].sz=tr[0].col=tr[0].rev=0;
	}
	return 0;
}
posted on 2020-11-26 18:45  Bwzhh  阅读(122)  评论(0编辑  收藏  举报