BZOJ5063旅游——非旋转treap
题目描述
小奇成功打开了大科学家的电脑。
大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序。初
始时,序列为1,2,...,n。
接着,大科学家进行m次操作来打乱顺序。每次操作有6步:
1、从序列开头(左端)取出A个数(此时序列剩下n-A个数)
2、从序列开头取出B个数
3、将第1步取出的A个数按原顺序放回序列开头
4、从序列开头取出C个数
5、将第2步取出的B个数逆序放回序列开头
6、将第4步取出的C个数按原顺序放回序列开头
你需要求出最终序列。
输入
第一行两个数n,m。接下来m行,每行三个数A,B,C。
n,m<=100000
输出
输出一行n个数表示最终序列。
样例输入
10 2
6 2 2
5 3 6
6 2 2
5 3 6
样例输出
1 2 8 7 3 9 6 5 4 10
非旋转treap模板题,直接按题意操作就好了,输出时直接dfs一遍整棵treap,注意不要忘记下传旋转标记。
#include<set> #include<map> #include<queue> #include<cmath> #include<stack> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int r[100010]; int ls[100010]; int rs[100010]; int size[100010]; int v[100010]; int s[100010]; int cnt; int n,m; int A,B,C; int x,y,z; int root; inline int build(int x) { int rt=++cnt; v[rt]=x; r[rt]=rand(); size[rt]=1; return rt; } inline void pushup(int rt) { size[rt]=size[ls[rt]]+size[rs[rt]]+1; } inline void pushdown(int rt) { if(s[rt]) { s[rt]^=1; s[ls[rt]]^=1; s[rs[rt]]^=1; swap(ls[rt],rs[rt]); } } inline void split(int rt,int &x,int &y,int k) { if(!rt) { x=y=0; return ; } pushdown(rt); if(size[ls[rt]]>=k) { y=rt; split(ls[rt],x,ls[y],k); pushup(rt); } else { x=rt; split(rs[rt],rs[x],y,k-size[ls[rt]]-1); pushup(rt); } } inline int merge(int x,int y) { if(!x||!y) { return x+y; } pushdown(x); pushdown(y); if(r[x]<r[y]) { rs[x]=merge(rs[x],y); pushup(x); return x; } else { ls[y]=merge(x,ls[y]); pushup(y); return y; } } inline int build(int l,int r) { if(l==r) { return build(l); } int mid=(l+r)>>1; return merge(build(l,mid),build(mid+1,r)); } inline void print(int rt) { pushdown(rt); if(ls[rt]) { print(ls[rt]); } printf("%d ",v[rt]); if(rs[rt]) { print(rs[rt]); } } int main() { srand(12378); scanf("%d%d",&n,&m); root=build(1,n); while(m--) { scanf("%d%d%d",&A,&B,&C); split(root,x,y,A); split(y,y,z,B); s[y]^=1; x=merge(x,z); split(x,x,z,C); root=merge(merge(x,y),z); } print(root); }