解题报告 『[SDOI2008]洞穴勘测(LCT)』
非常基础的增删边 + 询问,没什么好讲的。
代码实现如下:
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (register int i = (a); i <= (b); i++) const int maxn = 1e4 + 5; int n, m; int fa[maxn], rev[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 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; } 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; } } 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; } int main() { n = read(), m = read(); rep(i, 1, m) { int u, v; char opt[10]; scanf("%s", opt), u = read(), v = read(); if (opt[0] == 'C') link(u, v); if (opt[0] == 'D') cut(u, v); if (opt[0] == 'Q') { make_root(u); if (u == find(v)) printf("Yes\n"); else printf("No\n"); } } return 0; }