Description
Input
输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000。第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号。
Output
输出共一行,N个用空格隔开的正整数P1,P2,P3…Pn,Pi表示第i次操作前第i小的物品所在的位置。 注意:如果第i次操作前,第i小的物品己经在正确的位置Pi上,我们将区间[Pi,Pi]反转(单个物品)。
Sample Input
6
3 4 5 1 6 2
3 4 5 1 6 2
Sample Output
4 6 4 5 6 6
HINT
Source
Solution
预处理$[1, n]$中所有数的位置,每次把当前查找的数$x$旋到根上,其左儿子的子树大小就是答案。再对题意所述的区间加个reverse标记即可。
因为有区间加标记,所以最好加上头尾两个虚拟节点。
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct spaly 4 { 5 int c[2], fa, siz, rev; 6 }a[100005]; 7 pair<int, int> b[100005]; 8 9 void push_up(int k) 10 { 11 a[k].siz = a[a[k].c[0]].siz + a[a[k].c[1]].siz + 1; 12 } 13 14 void push_down(int k) 15 { 16 if(a[k].rev) 17 { 18 swap(a[k].c[0], a[k].c[1]), a[k].rev = 0; 19 a[a[k].c[0]].rev ^= 1, a[a[k].c[1]].rev ^= 1; 20 } 21 } 22 23 void rotate(int &k, int x) 24 { 25 int y = a[x].fa, z = a[y].fa; 26 int dy = a[y].c[1] == x, dz = a[z].c[1] == y; 27 if(k == y) k = x, a[x].fa = z; 28 else a[z].c[dz] = x, a[x].fa = z; 29 a[y].c[dy] = a[x].c[!dy], a[a[x].c[!dy]].fa = y; 30 a[x].c[!dy] = y, a[y].fa = x; 31 push_up(y); 32 } 33 34 void splay(int &k, int x) 35 { 36 while(k != x) 37 { 38 int y = a[x].fa, z = a[y].fa; 39 push_down(z), push_down(y), push_down(x); 40 if(k != y) 41 if(a[y].c[1] == x ^ a[z].c[1] == y) rotate(k, x); 42 else rotate(k, y); 43 rotate(k, x); 44 } 45 push_up(x); 46 } 47 48 int find(int k, int x) 49 { 50 if(!k) return 0; 51 push_down(k); 52 if(x <= a[a[k].c[0]].siz) return find(a[k].c[0], x); 53 if(x == a[a[k].c[0]].siz + 1) return k; 54 return find(a[k].c[1], x - a[a[k].c[0]].siz - 1); 55 } 56 57 int main() 58 { 59 int n, root, pos; 60 while(~scanf("%d", &n) && n) 61 { 62 for(int i = 1; i <= n; i++) 63 { 64 scanf("%d", &b[i].first); 65 b[i].second = i + 1; 66 } 67 sort(b + 1, b + n + 1); 68 for(int i = 1; i <= n + 2; i++) 69 { 70 a[i].fa = i + 1, a[i].c[0] = i - 1; 71 a[i].siz = i, a[i].c[1] = a[i].rev = 0; 72 } 73 a[n + 2].fa = 0, root = n + 2; 74 for(int i = 1; i <= n; i++) 75 { 76 splay(root, b[i].second); 77 pos = a[a[root].c[0]].siz; 78 printf("%d", pos); 79 if(i != n) printf(" "); 80 splay(root, find(root, i)); 81 splay(a[root].c[1], find(root, pos + 2)); 82 a[a[a[root].c[1]].c[0]].rev ^= 1; 83 } 84 puts(""); 85 } 86 return 0; 87 }
双倍经验的时候到了(。・ω・)ノ゙BZOJ3506 我是雷锋我骄傲。