http://acm.hdu.edu.cn/showproblem.php?pid=1890
题意:有一个无序序列,经过不断地翻转,使得最后的序列是一个升序的序列,而且如果相同数字要使在原本序列靠前的在前面。对于每一个位置,输出于哪个位置翻转。
思路:想通了之后其实挺简单的,不过挺巧妙。一开始先记录每一个位的pos,并对数组升序排序,然后我们从小到大枚举数组里的元素,对于每个元素,我们可以知道:i 就是翻转后应当在序列中的位置,a[i].pos就是它在原序列的位置。这个时候,我们只要在建树的时候利用中序遍历就是原数组的样子的性质,让节点的值就是它在原数组的位置,即建一个新的节点的时候,x 就是在原数组中的编号,例如样例:3 4 5 1 6 2,那么对应的节点的值就是 1 2 3 4 5 6 了。然后对于每一个询问,我们知道了它在原序列的位置,我们将它的位置(即节点本身的值)旋转到根节点,那么它的左子树的 sz 就是它目前所在的位置(因为一开始多了一个节点),然后再对 目标位置 和 所在的位置进行区间翻转,就可以完成了。
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #include <cmath> 7 #include <queue> 8 #include <vector> 9 using namespace std; 10 #define INF 0x7fffffff 11 #define lson ch[x][0] 12 #define rson ch[x][1] 13 #define keytree ch[ch[root][1]][0] 14 #define rootkey ch[root][1] 15 #define N 300000 16 struct node 17 { 18 int val, id; 19 }a[N]; 20 struct SplayTree { 21 int num[N], sz[N], fa[N], ch[N][2], root, rev[N]; 22 int n; 23 24 void PushUp(int x) { 25 sz[x] = sz[lson] + sz[rson] + 1; 26 } 27 28 void PushDown(int x) { 29 if(rev[x]) { 30 swap(lson, rson); 31 if(lson) rev[lson] ^= 1; 32 if(rson) rev[rson] ^= 1; 33 rev[x] = 0; 34 } 35 } 36 37 int NewNode(int f, int k, int kind) { 38 int x = k; 39 fa[x] = f; 40 rev[x] = ch[x][0] = ch[x][1] = 0; 41 sz[x] = 1; ch[f][kind] = x; 42 return x; 43 } 44 45 void Build(int l, int r, int &x, int f, int kind) { 46 if(l > r) return ; 47 int m = (l + r) >> 1; 48 x = NewNode(f, m, kind); 49 Build(l, m - 1, ch[x][0], x, 0); 50 Build(m + 1, r, ch[x][1], x, 1); 51 PushUp(x); 52 } 53 54 void Init() { 55 root = 0; 56 ch[0][0] = ch[0][1] = fa[0] = rev[0] = sz[0] = 0; 57 root = NewNode(0, n + 1, 0); 58 rootkey = NewNode(root, n + 2, 1); 59 sz[root] = 2; 60 Build(1, n, keytree, rootkey, 0); 61 PushUp(rootkey); PushUp(root); 62 } 63 64 void Rotate(int x, int kind) { 65 int y = fa[x], z = fa[y]; 66 PushDown(y); PushDown(x); 67 ch[y][!kind] = ch[x][kind]; 68 if(ch[x][kind]) fa[ch[x][kind]] = y; 69 if(z) { 70 if(y == ch[z][0]) ch[z][0] = x; 71 else ch[z][1] = x; 72 } 73 fa[x] = z; fa[y] = x; 74 ch[x][kind] = y; 75 PushUp(y); 76 } 77 78 void Splay(int x, int goal) { 79 PushDown(x); 80 while(fa[x] != goal) { 81 int y = fa[x], z = fa[y]; 82 PushDown(z); PushDown(y); PushDown(x); 83 int kind1 = x == ch[y][0]; 84 int kind2 = y == ch[z][0]; 85 if(z == goal) { 86 Rotate(x, kind1); 87 } else { 88 if(kind1 == kind2) Rotate(y, kind1); 89 else Rotate(x, kind1); 90 Rotate(x, kind2); 91 } 92 } 93 PushUp(x); 94 if(!goal) root = x; 95 } 96 97 void RTO(int k, int goal) { 98 int x = root; 99 PushDown(x); 100 while(sz[lson] + 1 != k) { 101 if(sz[lson] >= k) x = lson; 102 else k -= sz[lson] + 1, x = rson; 103 PushDown(x); 104 } 105 Splay(x, goal); 106 } 107 108 void Travel(int x) { 109 if(lson) Travel(lson); 110 printf("travel : %d\n", x); 111 if(rson) Travel(rson); 112 PushUp(x); 113 } 114 115 int Suf(int x) { // 找后继 116 if(rson) { 117 PushDown(x); 118 x = rson; 119 while(lson) { 120 x = lson; 121 PushDown(x); 122 } 123 } 124 return x; 125 } 126 127 int Query(int l, int r) { 128 Splay(r, 0); // 把原来节点的位置旋转到root位置 129 int ans = sz[ch[root][0]]; // 因为多了一个节点,所以不用+1 130 RTO(l, 0); // 把第l个数的前一个旋到root 131 Splay(Suf(r), root); // 把后继旋到ch[root][1] 132 rev[keytree] ^= 1; //区间翻转 133 return ans; 134 } 135 136 }spy; 137 138 bool cmp(const node &a, const node &b) { 139 if(a.val == b.val) return a.id < b.id; 140 return a.val < b.val; 141 } 142 143 int main() { 144 int n; 145 while(scanf("%d", &n), n) { 146 spy.n = n; 147 for(int i = 1; i <= n; i++) { 148 scanf("%d", &spy.num[i]); 149 a[i].id = i; 150 a[i].val = spy.num[i]; 151 } 152 sort(a + 1, a + 1 + n, cmp); 153 spy.Init(); 154 for(int i = 1; i <= n; i++) { 155 int ans; 156 ans = spy.Query(i, a[i].id); 157 if(i == n) printf("%d\n", ans); 158 else printf("%d ", ans); 159 } 160 } 161 return 0; 162 }
时间: 2024-10-13 05:40:52