http://acm.hdu.edu.cn/showproblem.php?pid=4453
题意:很多种操作:1、add x,将从光标起的 k2 个数全部加上 x;2、reverse,将从光标起的 k1 个数全部反转;3、insert x,在光标处的后一位插入值为 x 的数;4、delete,删除光标所在位置的数;5、move x,如果x是2,将光标右移,否则将光标左移。6、查询光标所在位置的值。
思路:在ACM中第一次写了6000+bytes的代码,把Splay几乎所有操作都汇集了,是一个很好的入门题目(虽然写了好久好久)。Splay是先插入两个结点,即0号节点下面的root,root的右孩子。Splay是一棵二叉树,满足左儿子比节点小,右儿子比节点大,中序遍历出来的结果就是原来数组的结果。所以我们在插入数组的时候,只要将数组插入到 ch[root][1] 的左孩子 ch[ch[root][1][0] (我的代码中的keytree) 的位置,那么就可以对这些数进行区间操作,并且这些数都是按顺序的。Splay就是利用这样的性质来完成各种操作的。注意因为一开始插入了两个点,所以实际上SplayTree的节点有 n + 2 个,数组中的元素标号从 2 开始到 n + 1。还要注意有 Insert 操作所以数组开大点,有一次TLE是因为这个。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <string> 7 #include <iostream> 8 #include <stack> 9 #include <map> 10 #include <queue> 11 using namespace std; 12 #define N 1000010 13 #define INF 0x3f3f3f3f 14 #define lson ch[x][0] 15 #define rson ch[x][1] 16 #define keytree ch[ch[root][1]][0] 17 struct SplayTree 18 { 19 int fa[N], ch[N][2], col[N], rev[N], sz[N], val[N], cnt, root, num[N]; 20 int n, tol, k1, k2; 21 22 int NewNode(int w, int f, int kind) 23 { 24 cnt++; 25 rev[cnt] = col[cnt] = ch[cnt][0] = ch[cnt][1] = 0; 26 sz[cnt] = 1; val[cnt] = w; fa[cnt] = f; 27 ch[f][kind] = cnt; 28 return cnt; 29 } 30 31 void PushUp(int x) 32 { 33 sz[x] = sz[lson] + sz[rson] + 1; 34 } 35 36 void PushDown(int x) 37 { 38 if(rev[x]) { 39 swap(lson, rson); 40 if(lson) rev[lson] ^= 1; 41 if(rson) rev[rson] ^= 1; 42 rev[x] = 0; 43 } 44 if(col[x]) { 45 if(lson) { 46 col[lson] += col[x]; 47 val[lson] += col[x]; 48 } 49 if(rson) { 50 col[rson] += col[x]; 51 val[rson] += col[x]; 52 } 53 col[x] = 0; 54 } 55 } 56 57 void Build(int l, int r, int &x, int f, int kind) 58 { 59 if(r < l) return ; 60 int m = (l + r) >> 1; 61 x = NewNode(num[m], f, kind); 62 Build(l, m - 1, ch[x][0], x, 0); 63 Build(m + 1, r, ch[x][1], x, 1); 64 PushUp(x); 65 } 66 67 void Init() // 初始化 68 { 69 cnt = root = 0; 70 col[0] = fa[0] = rev[0] = val[0] = ch[0][0] = ch[0][1] = sz[0] = 0; 71 root = NewNode(0, 0, 1); // 先开两个节点,然后把数组元素放进 keytree 的位置 72 ch[root][1] = NewNode(0, root, 1); 73 sz[root] = 2; 74 Build(1, n, keytree, ch[root][1], 0); 75 PushUp(ch[root][1]); PushUp(root); 76 } 77 78 void Rotate(int x, int kind) 79 { 80 int y = fa[x], z = fa[y]; 81 PushDown(y); PushDown(x); 82 ch[y][!kind] = ch[x][kind]; 83 if(ch[x][kind]) fa[ch[x][kind]] = y; 84 fa[y] = x; fa[x] = z; 85 if(z) { 86 if(ch[z][0] == y) ch[z][0] = x; 87 else ch[z][1] = x; 88 } 89 ch[x][kind] = y; 90 PushUp(y); 91 } 92 93 void Splay(int x, int goal) 94 { 95 while(fa[x] != goal) { 96 int y = fa[x], z = fa[y]; 97 PushDown(z); PushDown(y); PushDown(x); 98 int kind1 = ch[y][0] == x; 99 int kind2 = ch[z][0] == y; 100 if(z == goal) { 101 Rotate(x, kind1); 102 } else { 103 if(kind1 == kind2) { 104 Rotate(y, kind2); 105 } else { 106 Rotate(x, kind1); 107 } 108 Rotate(x, kind2); 109 } 110 // printf("%d, %d, %d ", x, fa[x], goal); 111 } 112 PushUp(x); 113 if(goal == 0) root = x; 114 } 115 116 void RTO(int k, int goal) // 将第k个元素旋转到0号节点下面 117 { 118 int x = root; 119 PushDown(x); 120 while(1) { 121 if(k <= sz[lson]) x = lson; 122 else if(k == sz[lson] + 1) break; 123 else { 124 k -= sz[lson] + 1; 125 x = rson; 126 } 127 PushDown(x); 128 } 129 Splay(x, goal); 130 } 131 132 void Insert(int val, int index) 133 { 134 RTO(index, 0); RTO(index + 1, root); 135 keytree = NewNode(val, ch[root][1], 0); 136 PushUp(ch[root][1]); PushUp(root); 137 // Splay(keytree, 0); 138 } 139 140 int Delete(bool kind) 141 { 142 int w; 143 if(kind) { 144 RTO(1, 0); RTO(3, root); 145 w = val[keytree]; 146 keytree = 0; 147 } else { 148 int ed = sz[root]; 149 RTO(ed - 2, 0); RTO(ed, root); 150 w = val[keytree]; 151 keytree = 0; 152 } 153 PushUp(ch[root][1]); PushUp(root); 154 // Splay(root, 0); 155 return w; 156 } 157 158 void Move(int kind) // 光标移动, 如果向左移动就删除最后的元素插到最前面, 向右移动反之 159 { 160 int w; 161 if(kind == 1) { 162 w = Delete(0); 163 Insert(w, 1); 164 } else { 165 w = Delete(1); 166 Insert(w, sz[root] - 1); 167 } 168 } 169 170 void Reverse() 171 { 172 RTO(1, 0); 173 // Debug(root); 174 RTO(k1 + 2, root); 175 // puts("----------------"); 176 // Debug(root); 177 // puts("----------------"); 178 rev[keytree] ^= 1; 179 // swap(ch[keytree][0], ch[keytree][1]); 180 PushUp(ch[root][1]); PushUp(root); 181 } 182 183 void Add(int w) 184 { 185 RTO(1, 0); RTO(k2 + 2, root); 186 // printf("add "); 187 col[keytree] += w; 188 val[keytree] += w; 189 PushUp(ch[root][1]); PushUp(root); 190 } 191 192 int Query() // 查询操作将要查询的数移动到根节点直接查询 193 { 194 RTO(2, 0); 195 // printf("%d ", root); 196 return val[root]; 197 } 198 199 void Debug(int x) 200 { 201 if(lson) Debug(lson); 202 printf("%d : %d, %d, %d, %d ", val[x], val[lson], val[rson], lson, rson); 203 if(rson) Debug(rson); 204 } 205 }splay; 206 207 int main() 208 { 209 int q, cas = 1; 210 while(~scanf("%d%d%d%d", &splay.n, &q, &splay.k1, &splay.k2), splay.n + q + splay.k1 + splay.k2) { 211 for(int i = 1; i <= splay.n; i++) scanf("%d", &splay.num[i]); 212 splay.Init(); 213 char s[20]; 214 printf("Case #%d: ", cas++); 215 for(int i = 1; i <= q; i++) { 216 scanf("%s", s); 217 int x; 218 if(s[0] == 'q') printf("%d ", splay.Query()); 219 else if(s[0] == 'a') { 220 scanf("%d", &x); 221 splay.Add(x); 222 } else if(s[0] == 'r') { 223 splay.Reverse(); 224 } else if(s[0] == 'i') { 225 scanf("%d", &x); 226 splay.Insert(x, 2); 227 } else if(s[0] == 'd') { 228 splay.Delete(1); 229 } else if(s[0] == 'm') { 230 scanf("%d", &x); 231 splay.Move(x); 232 } 233 // splay.Debug(splay.root); 234 } 235 } 236 return 0; 237 }