Splay
Splay
嗯,之前的博客。
重新写了个splay模板,普通平衡树。
1 #include <cstdio> 2 3 const int N = 100010, INF = 0x7f7f7f7f; 4 5 int val[N], s[N][2], fa[N], cnt[N], S[N], Sp, root, tot, siz[N]; 6 7 void out(int p = root) { 8 if(s[p][0]) { 9 out(s[p][0]); 10 } 11 printf("%d ", val[p]); 12 if(s[p][1]) { 13 out(s[p][1]); 14 } 15 if(p == root) { 16 puts(""); 17 } 18 return; 19 } 20 21 inline void pushup(int x) { 22 siz[x] = siz[s[x][0]] + siz[s[x][1]] + cnt[x]; 23 if(!fa[x]) { 24 root = x; 25 } 26 return; 27 } 28 29 inline void rotate(int x) { 30 int y = fa[x]; 31 int z = fa[y]; 32 bool f = s[y][1] == x; 33 34 fa[x] = z; 35 if(z) { 36 s[z][s[z][1] == y] = x; 37 } 38 s[y][f] = s[x][!f]; 39 if(s[x][!f]) { 40 fa[s[x][!f]] = y; 41 } 42 s[x][!f] = y; 43 fa[y] = x; 44 45 pushup(y); 46 pushup(x); 47 return; 48 } 49 50 inline void splay(int x, int g = 0) { 51 52 /*int y = x; 53 while(y) { 54 S[++Sp] = y; 55 y = fa[y]; 56 } 57 while(Sp) { 58 pushdown(S[Sp]); 59 Sp--; 60 }*/ 61 62 int y = fa[x]; 63 int z = fa[y]; 64 while(y != g) { 65 if(z != g) { 66 (s[z][1] == y) ^ (s[y][1] == x) ? 67 rotate(x) : rotate(y); 68 } 69 rotate(x); 70 y = fa[x]; 71 z = fa[y]; 72 } 73 return; 74 } 75 76 inline int np(int x, int f) { 77 ++tot; 78 fa[tot] = f; 79 val[tot] = x; 80 cnt[tot] = siz[tot] = 1; 81 return tot; 82 } 83 84 inline void init() { 85 root = np(INF, 0); 86 s[root][0] = np(-INF, root); 87 pushup(root); 88 return; 89 } 90 91 inline void insert(int x) { 92 int p = root; 93 while(1) { 94 // pushdown(p); 95 siz[p]++; 96 if(val[p] == x) { 97 cnt[p]++; 98 break; 99 } 100 if(val[p] > x && s[p][0]) { 101 p = s[p][0]; 102 } 103 else if(val[p] < x && s[p][1]) { 104 p = s[p][1]; 105 } 106 else { 107 bool f = x > val[p]; 108 s[p][f] = np(x, p); 109 p = s[p][f]; 110 break; 111 } 112 } 113 splay(p); 114 return; 115 } 116 117 inline int getPbyV(int x) { 118 int p = root; 119 while(1) { 120 if(val[p] > x && s[p][0]) { 121 p = s[p][0]; 122 } 123 else if(val[p] < x && s[p][1]) { 124 p = s[p][1]; 125 } 126 else { 127 break; 128 } 129 } 130 splay(p); 131 return p; 132 } 133 134 inline int getlP() { 135 int p = s[root][0]; 136 while(s[p][1]) { 137 p = s[p][1]; 138 } 139 return p; 140 } 141 142 inline int getrP() { 143 int p = s[root][1]; 144 while(s[p][0]) { 145 p = s[p][0]; 146 } 147 return p; 148 } 149 150 inline void delV(int x) { 151 x = getPbyV(x); 152 if(cnt[x] > 1) { 153 cnt[x]--; 154 pushup(x); 155 return; 156 } 157 int y = getlP(); 158 splay(y, x); 159 int z = s[x][1]; 160 fa[y] = 0; 161 fa[z] = y; 162 s[y][1] = z; 163 pushup(y); 164 return; 165 } 166 167 inline int getPreV(int x) { 168 int p = getPbyV(x); 169 if(val[p] < x) { 170 return val[p]; 171 } 172 p = getlP(); 173 splay(p); 174 return val[p]; 175 } 176 177 inline int getNexV(int x) { 178 int p = getPbyV(x); 179 if(val[p] > x) { 180 return val[p]; 181 } 182 p = getrP(); 183 splay(p); 184 return val[p]; 185 } 186 187 inline int getRbyV(int x) { 188 int p = getPbyV(x); 189 return siz[s[p][0]]; 190 } 191 192 inline int getVbyR(int k) { 193 k++; 194 int p = root; 195 while(1) { 196 if(siz[s[p][0]] >= k) { 197 p = s[p][0]; 198 } 199 else if(siz[s[p][0]] + cnt[p] >= k) { 200 break; 201 } 202 else { 203 k -= siz[s[p][0]] + cnt[p]; 204 p = s[p][1]; 205 } 206 } 207 splay(p); 208 return val[p]; 209 } 210 211 int main() { 212 init(); 213 int n; 214 scanf("%d", &n); 215 for(int i = 1, x, f; i <= n; i++) { 216 scanf("%d%d", &f, &x); 217 if(f == 1) { 218 insert(x); 219 } 220 else if(f == 2) { 221 delV(x); 222 } 223 else if(f == 3) { 224 int t = getRbyV(x); 225 printf("%d\n", t); 226 } 227 else if(f == 4) { 228 int t = getVbyR(x); 229 printf("%d\n", t); 230 } 231 else if(f == 5) { 232 int t = getPreV(x); 233 printf("%d\n", t); 234 } 235 else { 236 int t = getNexV(x); 237 printf("%d\n", t); 238 } 239 //out(); 240 } 241 242 return 0; 243 }
文艺平衡树,记得从上往下查的时候要pushdown。
1 #include <cstdio> 2 #include <algorithm> 3 4 const int N = 100010; 5 6 int val[N], fa[N], s[N][2], S[N], Sp, root, n, siz[N]; 7 bool rev[N]; 8 9 inline void pushup(int x) { 10 siz[x] = siz[s[x][0]] + siz[s[x][1]] + 1; 11 if(!fa[x]) { 12 root = x; 13 } 14 return; 15 } 16 17 inline void pushdown(int x) { 18 if(rev[x]) { 19 if(s[x][0]) { 20 rev[s[x][0]] ^= 1; 21 } 22 if(s[x][1]) { 23 rev[s[x][1]] ^= 1; 24 } 25 std::swap(s[x][0], s[x][1]); 26 rev[x] = 0; 27 } 28 return; 29 } 30 31 inline void rotate(int x) { 32 int y = fa[x]; 33 int z = fa[y]; 34 bool f = (s[y][1] == x); 35 36 fa[x] = z; 37 if(z) { 38 s[z][s[z][1] == y] = x; 39 } 40 s[y][f] = s[x][!f]; 41 if(s[x][!f]) { 42 fa[s[x][!f]] = y; 43 } 44 s[x][!f] = y; 45 fa[y] = x; 46 47 pushup(y); 48 pushup(x); 49 return; 50 } 51 52 inline void splay(int x, int g = 0) { 53 int y = x; 54 while(y != g) { 55 S[++Sp] = y; 56 y = fa[y]; 57 } 58 while(Sp) { 59 pushdown(S[Sp]); 60 Sp--; 61 } 62 63 y = fa[x]; 64 int z = fa[y]; 65 while(y != g) { 66 if(z != g) { 67 (s[z][1] == y) ^ (s[y][1] == x) ? 68 rotate(x) : rotate(y); 69 } 70 rotate(x); 71 y = fa[x]; 72 z = fa[y]; 73 } 74 return; 75 } 76 77 inline int getPbyR(int k) { 78 int p = root; 79 while(1) { 80 pushdown(p); 81 if(siz[s[p][0]] >= k) { 82 p = s[p][0]; 83 } 84 else if(siz[s[p][0]] + 1 == k) { 85 break; 86 } 87 else { 88 k -= siz[s[p][0]] + 1; 89 p = s[p][1]; 90 } 91 } 92 return p; 93 } 94 95 inline void reverse(int x, int y) { 96 y += 2; 97 x = getPbyR(x); 98 y = getPbyR(y); 99 splay(y); 100 splay(x, y); 101 rev[s[x][1]] ^= 1; 102 return; 103 } 104 105 void out(int x = root) { 106 pushdown(x); 107 if(s[x][0]) { 108 out(s[x][0]); 109 } 110 if(val[x] && val[x] <= n) { 111 printf("%d ", val[x]); 112 } 113 if(s[x][1]) { 114 out(s[x][1]); 115 } 116 return; 117 } 118 119 int build(int l, int r, int f) { 120 int mid = (l + r) >> 1; 121 int p = mid + 1; 122 val[p] = mid; 123 fa[p] = f; 124 if(l < mid) { 125 s[p][0] = build(l, mid - 1, p); 126 } 127 if(mid < r) { 128 s[p][1] = build(mid + 1, r, p); 129 } 130 pushup(p); 131 return p; 132 } 133 134 int main() { 135 136 int m; 137 scanf("%d%d", &n, &m); 138 root = build(0, n + 1, 0); 139 for(int i = 1, x, y; i <= m; i++) { 140 scanf("%d%d", &x, &y); 141 reverse(x, y); 142 } 143 out(); 144 return 0; 145 }
可以酌情往里面加空间回收,pushdown等。
例题(参考饕餮传奇):
列队(90pts) 郁闷的出纳员 宠物收养场 营业额统计 送花
永无乡(启发式合并) [ZJOI2006]书架:直接对节点"编号"进行操作,splay这个编号。
梦幻布丁(启发式合并):开若干个数版splay,维护每个颜色的位置集合。
排序机械臂 维护数列 [AHOI2006]文本编辑器
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 #define Max 500009 6 #define Min 500008 7 8 const int N = 500010, INF = 5e8 + 10, EPT = 0x3f3f3f3f; 9 10 int val[N], sum[N], tag[N], fa[N], s[N][2], S[N], Sp, stk[4500010], stp, ans[N], la[N], ra[N], siz[N], root, tot, A[N], n; 11 bool rev[N]; 12 char str[15]; 13 14 inline void exmax(int &a, const int &b) { 15 if(a < b) { 16 a = b; 17 } 18 return; 19 } 20 21 inline void pushup(int x) { 22 int ls = s[x][0], rs = s[x][1]; 23 siz[x] = siz[ls] + siz[rs] + 1; 24 if(!fa[x]) { 25 root = x; 26 } 27 sum[x] = sum[ls] + sum[rs] + val[x]; 28 ans[x] = val[x]; 29 if(ls && rs) { 30 exmax(ans[x], ans[ls]); 31 exmax(ans[x], ans[rs]); 32 exmax(ans[x], val[x] + la[rs]); 33 exmax(ans[x], val[x] + ra[ls]); 34 exmax(ans[x], ra[ls] + val[x] + la[rs]); 35 la[x] = std::max(la[ls], sum[ls] + val[x]); 36 exmax(la[x], sum[ls] + val[x] + la[rs]); 37 ra[x] = std::max(ra[rs], sum[rs] + val[x]); 38 exmax(ra[x], sum[rs] + val[x] + ra[ls]); 39 } 40 else if(ls) { 41 exmax(ans[x], ans[ls]); 42 exmax(ans[x], val[x] + ra[ls]); 43 ra[x] = std::max(val[x], val[x] + ra[ls]); 44 la[x] = std::max(la[ls], sum[ls] + val[x]); 45 } 46 else if(rs) { 47 exmax(ans[x], ans[rs]); 48 exmax(ans[x], val[x] + la[rs]); 49 la[x] = std::max(val[x], val[x] + la[rs]); 50 ra[x] = std::max(ra[rs], sum[rs] + val[x]); 51 } 52 else { 53 la[x] = ra[x] = val[x]; 54 } 55 return; 56 } 57 58 inline void pushdown(int x) { 59 int ls = s[x][0], rs = s[x][1]; 60 if(rev[x]) { 61 if(ls) { 62 rev[ls] ^= 1; 63 std::swap(la[ls], ra[ls]); 64 } 65 if(rs) { 66 rev[rs] ^= 1; 67 std::swap(la[rs], ra[rs]); 68 } 69 std::swap(s[x][0], s[x][1]); 70 rev[x] = 0; 71 } 72 if(tag[x] != EPT) { 73 int &c = tag[x]; 74 if(ls) { 75 val[ls] = tag[ls] = c; 76 sum[ls] = c * siz[ls]; 77 if(c >= 0) { 78 ans[ls] = la[ls] = ra[ls] = sum[ls]; 79 } 80 else { 81 ans[ls] = la[ls] = ra[ls] = c; 82 } 83 } 84 if(rs) { 85 val[rs] = tag[rs] = c; 86 sum[rs] = c * siz[rs]; 87 if(c >= 0) { 88 ans[rs] = la[rs] = ra[rs] = sum[rs]; 89 } 90 else { 91 ans[rs] = la[rs] = ra[rs] = c; 92 } 93 } 94 c = EPT; 95 } 96 return; 97 } 98 99 void out(int p = root) { 100 pushdown(p); 101 if(s[p][0]) { 102 out(s[p][0]); 103 } 104 printf("%d ", val[p]); 105 if(s[p][1]) { 106 out(s[p][1]); 107 } 108 if(p == root) { 109 puts(""); 110 } 111 return; 112 } 113 114 inline void rotate(int x) { 115 int y = fa[x]; 116 int z = fa[y]; 117 bool f = (s[y][1] == x); 118 119 fa[x] = z; 120 if(z) { 121 s[z][s[z][1] == y] = x; 122 } 123 s[y][f] = s[x][!f]; 124 if(s[x][!f]) { 125 fa[s[x][!f]] = y; 126 } 127 s[x][!f] = y; 128 fa[y] = x; 129 130 pushup(y); 131 pushup(x); 132 return; 133 } 134 135 inline void splay(int x, int g = 0) { 136 int y = x; 137 while(y != g) { 138 S[++Sp] = y; 139 y = fa[y]; 140 } 141 while(Sp) { 142 pushdown(S[Sp]); 143 Sp--; 144 } 145 146 y = fa[x]; 147 int z = fa[y]; 148 while(y != g) { 149 if(z != g) { 150 (s[z][1] == y) ^ (s[y][1] == x) ? 151 rotate(x) : rotate(y); 152 } 153 rotate(x); 154 y = fa[x]; 155 z = fa[y]; 156 } 157 return; 158 } 159 160 inline int getPbyR(int k) { 161 int p = root; 162 while(1) { 163 pushdown(p); 164 if(siz[s[p][0]] >= k) { 165 p = s[p][0]; 166 } 167 else if(siz[s[p][0]] + 1 == k) { 168 break; 169 } 170 else { 171 k -= (siz[s[p][0]] + 1); 172 p = s[p][1]; 173 } 174 } 175 // splay(p); 176 return p; 177 } 178 179 inline int split(int l, int r) { 180 l = getPbyR(l); 181 r = getPbyR(r); 182 splay(r); 183 splay(l, r); 184 return l; 185 } 186 187 inline void change(int l, int r, int c) { 188 int p = split(l, r + 2); 189 int x = s[p][1]; 190 tag[x] = val[x] = c; 191 sum[x] = siz[x] * c; 192 if(c >= 0) { 193 ans[x] = la[x] = ra[x] = sum[x]; 194 } 195 else { 196 ans[x] = la[x] = ra[x] = c; 197 } 198 pushup(p); 199 pushup(root); 200 return; 201 } 202 203 inline void reverse(int l, int r) { 204 int p = split(l, r + 2); 205 int x = s[p][1]; 206 rev[x] ^= 1; 207 std::swap(la[x], ra[x]); 208 pushup(p); 209 pushup(root); 210 return; 211 } 212 213 void del(int x) { 214 if(s[x][0]) { 215 del(s[x][0]); 216 } 217 if(s[x][1]) { 218 del(s[x][1]); 219 } 220 stk[++stp] = x; 221 return; 222 } 223 224 inline void exdel(int l, int r) { 225 int p = split(l, r + 2); 226 int x = s[p][1]; 227 del(x); 228 s[p][1] = 0; 229 pushup(p); 230 pushup(root); 231 return; 232 } 233 234 inline int np(int c, int f) { 235 int x; 236 if(!c) { 237 x = Min; 238 } 239 else if(c > n) { 240 x = Max; 241 } 242 else if(stp) { 243 x = stk[stp--]; 244 s[x][0] = s[x][1] = rev[x] = 0; 245 tag[x] = EPT; 246 } 247 else { 248 x = ++tot; 249 } 250 val[x] = A[c]; 251 fa[x] = f; 252 return x; 253 } 254 255 inline int build(int l, int r, int f) { 256 int mid = (l + r) >> 1; 257 int p = np(mid, f); 258 if(l < mid) { 259 s[p][0] = build(l, mid - 1, p); 260 } 261 if(mid < r) { 262 s[p][1] = build(mid + 1, r, p); 263 } 264 pushup(p); 265 return p; 266 } 267 268 inline void insert(int pos, int len) { 269 int p = split(pos + 1, pos + 2); 270 s[p][1] = build(1, len, p); 271 pushup(p); 272 pushup(root); 273 return; 274 } 275 276 inline int ask(int l, int r) { 277 int p = split(l, r + 2); 278 int ans = sum[s[p][1]]; 279 while(ans < -INF) { 280 ans += INF; 281 } 282 return ans; 283 } 284 285 int main() { 286 memset(tag, 0x3f, sizeof(tag)); 287 int m; 288 scanf("%d%d", &n, &m); 289 for(int i = 1; i <= n; i++) { 290 scanf("%d", &A[i]); 291 } 292 A[0] = A[n + 1] = -INF; 293 root = build(0, n + 1, 0); 294 //out(); 295 for(int i = 1, x, y; i <= m; i++) { 296 scanf("%s", str); 297 if(str[0] == 'I') { 298 scanf("%d%d", &x, &y); 299 for(int i = 1; i <= y; i++) { 300 scanf("%d", &A[i]); 301 } 302 n = y; 303 insert(x, y); 304 } 305 else if(str[0] == 'D') { 306 scanf("%d%d", &x, &y); 307 exdel(x, x + y - 1); 308 } 309 else if(str[0] == 'R') { 310 scanf("%d%d", &x, &y); 311 reverse(x, x + y - 1); 312 } 313 else if(str[0] == 'G') { 314 scanf("%d%d", &x, &y); 315 int t = ask(x, x + y - 1); 316 printf("%d\n", t); 317 } 318 else if(str[2] == 'X') { 319 printf("%d\n", ans[root]); 320 } 321 else { 322 int c; 323 scanf("%d%d%d", &x, &y, &c); 324 change(x, x + y - 1, c); 325 } 326 //out(); 327 } 328 329 return 0; 330 }
啊,假装splay过关了......
代码中易错点:
从上往下的操作比如insert,getLP,getPbyR等,要先pushdown。
断开/新建父子关系的时候注意要断完全。有区间赋0操作的时候tag默认设为别的。