树套树
TTT(Tree套Tree)
虽然有各种奇怪的套法......先用例题来解释吧。
二逼平衡树。(无数种树套树,还有两种分块,一种整体二分,一种vector的解法...)
题意:给定序列。
1.查询x在[l, r]的排名。
2.查询[l, r]中排名为k的值。
3.修改某个数。
4.查询[l, r]中x的前驱。
5.查询[l, r]中x的后继。
解:解法很多...大致可以通过外层树的类型分成两种:外层值域和外层位置。
内层树又可以选择平衡树或者线段树两种。
外层一般是线段树,也有用树状数组的。
①线段树套平衡树。
最经典的解法,外面是位置线段树,内部是维护权值的平衡树。
首先,可以归并建树。
操作一,对于区间对应的线段树上log个节点,查找比x小的数。答案+1即可。
操作二,在值域上二分,调用操作一判定。
操作三,对于它所在的log个平衡树,全部进行修改。
操作四/五,在区间对应的log个节点上分别查询前驱/后继,取max/min。
实现上可以用结构体封装...
线性建树的时候注意去重,反正我是手写了一个结构体...
注意操作1的x可能不在原序列中。
空间大小,每个节点插入log次,但是我开了哨兵,所以还要多8n的空间。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 6 const int M = 1500010, INF = 2147483647, N = 100010; 7 8 int tot, s[M][2], fa[M], siz[M], cnt[M], val[M]; 9 std::queue<int> Rest; 10 11 struct Node { 12 int x, y; 13 }node[N]; 14 15 struct Splay { 16 17 int root; 18 19 inline void pushup(int x) { 20 siz[x] = siz[s[x][0]] + siz[s[x][1]] + cnt[x]; 21 if(!fa[x]) { 22 root = x; 23 } 24 return; 25 } 26 27 inline void rotate(int x) { 28 int y = fa[x]; 29 int z = fa[y]; 30 bool f = (s[y][1] == x); 31 32 fa[x] = z; 33 if(z) { 34 s[z][s[z][1] == y] = x; 35 } 36 s[y][f] = s[x][!f]; 37 if(s[x][!f]) { 38 fa[s[x][!f]] = y; 39 } 40 s[x][!f] = y; 41 fa[y] = x; 42 43 pushup(y); 44 pushup(x); 45 return; 46 } 47 48 inline void splay(int x, int g = 0) { 49 int y = fa[x]; 50 int z = fa[y]; 51 while(y != g) { 52 if(z != g) { 53 (s[z][1] == y) ^ (s[y][1] == x) ? 54 rotate(x) : rotate(y); 55 } 56 rotate(x); 57 y = fa[x]; 58 z = fa[y]; 59 } 60 return; 61 } 62 63 inline int np(int c, int f, int sum = 1) { 64 int p; 65 if(Rest.empty()) { 66 p = ++tot; 67 } 68 else { 69 p = Rest.front(); 70 Rest.pop(); 71 } 72 fa[p] = f; 73 s[p][0] = s[p][1] = 0; 74 siz[p] = cnt[p] = sum; 75 val[p] = c; 76 return p; 77 } 78 79 inline void insert(int c) { 80 int p = root; 81 while(1) { 82 siz[p]++; 83 if(val[p] == c) { 84 cnt[p]++; 85 break; 86 } 87 if(c < val[p] && s[p][0]) { 88 p = s[p][0]; 89 } 90 else if(val[p] < c && s[p][1]) { 91 p = s[p][1]; 92 } 93 else { 94 bool f = (val[p] < c); 95 s[p][f] = np(c, p); 96 break; 97 } 98 } 99 splay(p); 100 return; 101 } 102 103 inline int getPbyV(int c) { // if exist return Node else return neighbor 104 int p = root; 105 while(1) { 106 if(val[p] == c) { 107 break; 108 } 109 else if(c < val[p] && s[p][0]) { 110 p = s[p][0]; 111 } 112 else if(val[p] < c && s[p][1]) { 113 p = s[p][1]; 114 } 115 else { 116 break; 117 } 118 } 119 return p; 120 } 121 122 inline int getRP() { 123 int p = s[root][1]; 124 while(s[p][0]) { 125 p = s[p][0]; 126 } 127 return p; 128 } 129 130 inline int getLP() { 131 int p = s[root][0]; 132 while(s[p][1]) { 133 p = s[p][1]; 134 } 135 return p; 136 } 137 138 inline void del(int c) { 139 int x = getPbyV(c); 140 splay(x); 141 if(cnt[x] > 1) { 142 cnt[x]--; 143 siz[x]--; 144 return; 145 } 146 int y = getRP(); 147 splay(y, x); 148 fa[y] = 0; 149 s[y][0] = s[x][0]; 150 fa[s[x][0]] = y; 151 pushup(y); 152 Rest.push(x); 153 return; 154 } 155 156 inline int getPre(int c) { 157 int p = getPbyV(c); 158 splay(p); 159 if(val[p] >= c) { 160 p = getLP(); 161 splay(p); 162 return val[p]; 163 } 164 else { 165 return val[p]; 166 } 167 } 168 169 inline int getNex(int c) { 170 int p = getPbyV(c); 171 splay(p); 172 if(val[p] <= c) { 173 p = getRP(); 174 splay(p); 175 return val[p]; 176 } 177 else { 178 return val[p]; 179 } 180 } 181 182 inline int getRbyV(int c) { 183 int p = getPbyV(c); 184 splay(p); 185 if(val[p] < c) { 186 p = getRP(); 187 splay(p); 188 } 189 return siz[s[p][0]]; 190 } 191 192 int build(int l, int r, int f) { 193 if(l == r) { 194 return np(node[r].x, f, node[r].y); 195 } 196 int mid = (l + r) >> 1; 197 int p = np(node[mid].x, f, node[mid].y); 198 if(l < mid) { 199 s[p][0] = build(l, mid - 1, p); 200 } 201 if(mid < r) { 202 s[p][1] = build(mid + 1, r, p); 203 } 204 pushup(p); 205 return p; 206 } 207 208 inline void init(int *a, int n) { 209 int t = 1; 210 node[1].x = a[1]; 211 node[1].y = 1; 212 for(int i = 2; i <= n; i++) { 213 if(a[i] != a[i - 1]) { 214 node[++t].x = a[i]; 215 node[t].y = 0; 216 } 217 node[t].y++; 218 } 219 root = build(1, t, 0); 220 insert(INF); 221 insert(-INF); 222 return; 223 } 224 225 void out(int x) { 226 if(x == 0) { 227 x = root; 228 } 229 if(s[x][0]) { 230 out(s[x][0]); 231 } 232 for(int i = 1; i <= cnt[x]; i++) { 233 printf("%d ", val[x]); 234 } 235 if(s[x][1]) { 236 out(s[x][1]); 237 } 238 return; 239 } 240 // over 241 }spt[N << 2]; 242 243 int large[N << 2], small[N << 2], a[N], b[N], c[N]; 244 245 inline void pushup(int o) { 246 int ls = o << 1, rs = o << 1 | 1; 247 small[o] = std::min(small[ls], small[rs]); 248 large[o] = std::max(large[ls], large[rs]); 249 return; 250 } 251 252 int getRank(int L, int R, int v, int l, int r, int o) { 253 if(L <= l && r <= R) { 254 return spt[o].getRbyV(v) - 1; 255 } 256 int mid = (l + r) >> 1, ans = 0; 257 if(L <= mid) { 258 ans += getRank(L, R, v, l, mid, o << 1); 259 } 260 if(mid < R) { 261 ans += getRank(L, R, v, mid + 1, r, o << 1 | 1); 262 } 263 return ans; 264 } 265 266 int getPre(int L, int R, int v, int l, int r, int o) { 267 if(L <= l && r <= R) { 268 return spt[o].getPre(v); 269 } 270 int ans = -INF, mid = (l + r) >> 1; 271 if(L <= mid) { 272 ans = std::max(ans, getPre(L, R, v, l, mid, o << 1)); 273 } 274 if(mid < R) { 275 ans = std::max(ans, getPre(L, R, v, mid + 1, r, o << 1 | 1)); 276 } 277 return ans; 278 } 279 280 int getNex(int L, int R, int v, int l, int r, int o) { 281 if(L <= l && r <= R) { 282 return spt[o].getNex(v); 283 } 284 int mid = (l + r) >> 1, ans = INF; 285 if(L <= mid) { 286 ans = std::min(ans, getNex(L, R, v, l, mid, o << 1)); 287 } 288 if(mid < R) { 289 ans = std::min(ans, getNex(L, R, v, mid + 1, r, o << 1 | 1)); 290 } 291 return ans; 292 } 293 294 void change(int p, int v, int l, int r, int o) { 295 spt[o].del(a[p]); 296 spt[o].insert(v); 297 if(l == r) { 298 a[p] = large[o] = small[o] = v; 299 return; 300 } 301 int mid = (l + r) >> 1; 302 if(p <= mid) { 303 change(p, v, l, mid, o << 1); 304 } 305 else { 306 change(p, v, mid + 1, r, o << 1 | 1); 307 } 308 pushup(o); 309 return; 310 } 311 312 inline void merge(int l, int r) { 313 memcpy(c + l, b + l, (r - l + 1) * sizeof(int)); 314 int mid = (l + r) >> 1; 315 int i = l, j = mid + 1, t = l; 316 while(t <= r) { 317 if(j > r || (i <= mid && c[i] < c[j])) { 318 b[t++] = c[i]; 319 i++; 320 } 321 else { 322 b[t++] = c[j]; 323 j++; 324 } 325 } 326 return; 327 } 328 329 void build(int l, int r, int o) { 330 if(l == r) { 331 spt[o].init(b + r - 1, 1); 332 small[o] = large[o] = b[r]; 333 return; 334 } 335 int mid = (l + r) >> 1; 336 build(l, mid, o << 1); 337 build(mid + 1, r, o << 1 | 1); 338 merge(l, r); 339 spt[o].init(b + l - 1, r - l + 1); 340 pushup(o); 341 return; 342 } 343 344 int getMax(int L, int R, int l, int r, int o) { 345 if(L <= l && r <= R) { 346 return large[o]; 347 } 348 int mid = (l + r) >> 1, ans = -INF; 349 if(L <= mid) { 350 ans = std::max(ans, getMax(L, R, l, mid, o << 1)); 351 } 352 if(mid < R) { 353 ans = std::max(ans, getMax(L, R, mid + 1, r, o << 1 | 1)); 354 } 355 return ans; 356 } 357 358 int getMin(int L, int R, int l, int r, int o) { 359 if(L <= l && r <= R) { 360 return small[o]; 361 } 362 int mid = (l + r) >> 1, ans = INF; 363 if(L <= mid) { 364 ans = std::min(ans, getMin(L, R, l, mid, o << 1)); 365 } 366 if(mid < R) { 367 ans = std::min(ans, getMin(L, R, mid + 1, r, o << 1 | 1)); 368 } 369 return ans; 370 } 371 372 void out(int l, int r, int o) { 373 printf("out %d %d : ", l, r); 374 spt[o].out(0); 375 puts(""); 376 if(l == r) { 377 return; 378 } 379 int mid = (l + r) >> 1; 380 out(l, mid, o << 1); 381 out(mid + 1, r, o << 1 | 1); 382 return; 383 } 384 385 int main() { 386 387 int n, m; 388 scanf("%d%d", &n, &m); 389 for(int i = 1; i <= n; i++) { 390 scanf("%d", &a[i]); 391 b[i] = a[i]; 392 } 393 build(1, n, 1); 394 395 for(int i = 1, x, y, z, f; i <= m; i++) { 396 scanf("%d%d%d", &f, &x, &y); 397 if(f == 1) { 398 scanf("%d", &z); 399 int t = getRank(x, y, z, 1, n, 1); 400 printf("%d\n", t + 1); 401 } 402 else if(f == 2) { 403 scanf("%d", &z); 404 int l = getMin(x, y, 1, n, 1), r = getMax(x, y, 1, n, 1); 405 while(l < r) { 406 int mid = (l + r + 1) >> 1; 407 if(getRank(x, y, mid, 1, n, 1) + 1 <= z) { 408 l = mid; 409 } 410 else { 411 r = mid - 1; 412 } 413 } 414 printf("%d\n", r); 415 } 416 else if(f == 3) { 417 change(x, y, 1, n, 1); 418 } 419 else if(f == 4) { 420 scanf("%d", &z); 421 int t = getPre(x, y, z, 1, n, 1); 422 printf("%d\n", t); 423 } 424 else if(f == 5) { 425 scanf("%d", &z); 426 int t = getNex(x, y, z, 1, n, 1); 427 printf("%d\n", t); 428 } 429 } 430 431 return 0; 432 }
洛谷上卡时1961ms过了,不开O(2)是信仰。然而石室老爷机T了两个点...
别的做法懒得写了。
搞点例题来吧。因为带修主席树的本质是树套树所以也会放在这里。