题目描述
给定一个1...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
样例输出
1 2 8 7 3 9 6 5 4 10
题解
Splay裸题
题目中操作显然可以直接使用Splay解决
然而本题卡常,直接模拟每次的6个步骤会T得很惨。。。
考虑一下操作的实质:把第$A+1$个到第$A+B$个拿出来,再翻转一下放回到序列的第C个的后面。这个过程可以直接两次操作完成。常数减到直接模拟的1/3。
注意最后输出时不能对于每一个都find一遍(这样Splay的均摊分析不成立,除非find后splay到根),最好的方法是dfs一遍Splay Tree,此时不要忘记pushdown。
另外亲测数组版比结构体版慢了1倍左右= =
#include <cstdio> #include <cctype> #include <algorithm> using namespace std; #define N 100010 struct data { int fa , c[2] , si , rev; }a[N]; int root , ans[N] , tot; inline void rever(int x) { swap(a[x].c[0] , a[x].c[1]) , a[x].rev ^= 1; } inline void pushup(int x) { a[x].si = a[a[x].c[0]].si + a[a[x].c[1]].si + 1; } inline void pushdown(int x) { if(a[x].rev) rever(a[x].c[0]) , rever(a[x].c[1]) , a[x].rev = 0; } inline void rotate(int &k , int x) { int y = a[x].fa , z = a[y].fa , l = (a[y].c[1] == x) , r = l ^ 1; if(y == k) k = x; else a[z].c[a[z].c[1] == y] = x; a[x].fa = z , a[y].fa = x , a[a[x].c[r]].fa = y , a[y].c[l] = a[x].c[r] , a[x].c[r] = y; pushup(y) , pushup(x); } inline void splay(int &k , int x) { int y , z; while(x != k) { y = a[x].fa , z = a[y].fa; if(y != k) { if((a[y].c[0] == x) ^ (a[z].c[0] == y)) rotate(k , x); else rotate(k , y); } rotate(k , x); } } int find(int k , int x) { pushdown(k); if(x <= a[a[k].c[0]].si) return find(a[k].c[0] , x); else if(x > a[a[k].c[0]].si + 1) return find(a[k].c[1] , x - a[a[k].c[0]].si - 1); else return k; } inline int split(int l , int r) { int x = find(root , l) , y = find(root , r + 2); splay(root , x) , splay(a[root].c[1] , y); return a[a[root].c[1]].c[0]; } int build(int l , int r) { if(l > r) return 0; int mid = (l + r) >> 1; a[mid].c[0] = build(l , mid - 1) , a[a[mid].c[0]].fa = mid; a[mid].c[1] = build(mid + 1 , r) , a[a[mid].c[1]].fa = mid; pushup(mid); return mid; } void dfs(int x) { if(!x) return; pushdown(x) , dfs(a[x].c[0]) , ans[++tot] = x , dfs(a[x].c[1]); } inline char nc() { static char buf[100000] , *p1 , *p2; return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ; } inline int read() { int ret = 0; char ch = nc(); while(!isdigit(ch)) ch = nc(); while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc(); return ret; } int main() { int n = read() , m = read() , i , A , B , C , x; root = build(1 , n + 2); for(i = 1 ; i <= m ; i ++ ) { A = read() , B = read() , C = read(); x = split(A + 1 , A + B) , a[a[x].fa].c[0] = 0 , pushup(a[x].fa) , pushup(root) , rever(x); split(C + 1 , C) , a[x].fa = a[root].c[1] , a[a[x].fa].c[0] = x , pushup(a[x].fa) , pushup(root); } dfs(root); for(i = 2 ; i <= n + 1 ; i ++ ) printf("%d " , ans[i] - 1); return 0; }