解题报告 『[HNOI2010]弹飞绵羊(LCT)』
LCT的裸题,如果u能到v就link(u, v),如果会被弹飞就link(u, n + 1);
第二个操作先cut再link然后赋值就行了。
代码实现如下:
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (register int i = (a); i <= (b); i++) const int maxn = 2e5 + 5; int n, m; int fa[maxn], rev[maxn], val[maxn], size[maxn], ch[maxn][3]; int get(int x) {return x == ch[fa[x]][1];} int is_root(int x) {return x ^ ch[fa[x]][0] && x ^ ch[fa[x]][1];} int read() { int x = 0, flag = 0; char ch = ' '; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar(); if (ch == '-') { flag = 1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch ^ '0'); ch = getchar(); } return flag ? -x : x; } void push_down(int x) { if (rev[x]) { ch[x][0] ^= ch[x][1] ^= ch[x][0] ^= ch[x][1]; rev[ch[x][0]] ^= 1; rev[ch[x][1]] ^= 1; rev[x] = 0; } } void maintain(int x) { size[0] = 0; size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; } void update(int x) { if (!is_root(x)) update(fa[x]); push_down(x); } void rotate(int x) { int y = fa[x], z = fa[y], chx = get(x), chy = get(y); if (!is_root(y)) ch[z][chy] = x; ch[y][chx] = ch[x][chx ^ 1]; fa[ch[x][chx ^ 1]] = y; ch[x][chx ^ 1] = y; fa[y] = x; fa[x] = z; maintain(y); maintain(x); maintain(z); } void splay(int x) { update(x); for (register int f = fa[x]; f = fa[x], !is_root(x); rotate(x)) if (!is_root(f)) rotate(get(x) == get(f) ? f : x); } void access(int x) { for (register int p = 0; x; p = x, x = fa[x]) { splay(x); ch[x][1] = p; maintain(x); } } int find(int x) { access(x); splay(x); while (ch[x][0]) { push_down(x); x = ch[x][0]; } return x; } void make_root(int x) { access(x); splay(x); rev[x] ^= 1; push_down(x); } void split(int u, int v) { make_root(u); access(v); splay(v); } void link(int u, int v) { make_root(u); if (u ^ find(v)) fa[u] = v; else return; } void cut(int u, int v) { split(u, v); if (ch[v][0] == u && !ch[u][1]) fa[u] = ch[v][0] = 0; else return; } void write(int x) { if (x < 0) { putchar('-'); x = -x; } if (x > 9) write(x / 10); putchar(x % 10 + '0'); } int main() { n = read(); rep(i, 1, n) { val[i] = read(); link(i, i + val[i] <= n ? i + val[i] : n + 1); } m = read(); rep(i, 1, m) { int j, opt; opt = read(), j = read() + 1; switch(opt) { case(1): { split(j, n + 1); write(size[n + 1] - 1); printf("\n"); break; } case(2): { int k; k = read(); cut(j, j + val[j] <= n ? j + val[j] : n + 1); link(j, j + k <= n ? j + k : n + 1); val[j] = k; break; } } } return 0; }