2020 牛客 NOIP 赛前集训营 提高级(第四场) 平衡树模板
B-色球
【题目描述】
牛牛有\(n\)种颜色的彩色小球(编号\(1\)到\(n\)),每种颜色的小球他都有无限多个。他
还有\(n\)个球桶(编号\(1\)到\(n\)),球桶的内径与小球直径相当且高度是无限大的,因
此能容纳无限多的小球。他想用这些小球和球桶玩游戏。
一开始这些球桶都是空的,紧接着他会顺次地做\(m\)个操作,每个操作都是以下 \(3\)
类操作中的一个。
- 把\(x\)个颜色为\(y\)的彩色小球放到第\(z\)个桶的最上面(\(push\) \(x\) \(y\) \(z\)) ;
- 把最上面的\(x\)个小球从第 \(z\) 个桶内拿出来(\(pop\) \(x\) \(z\)) ;
- 把第\(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;
}