Gym100512D Dynamic LCA
题目来源:2012-2013 Summer Petrozavodsk Camp, Andrew Stankevich Contest 42
记当前根为 root,查询的两个节点为 u 和 v,子树、LCA 指以 1 为根的子树、LCA
- u 和 v 都不在 root 所在子树
答案为 LCA(u, v) - u 和 v 都在 root 所在子树
- 若 u 和 v 都在以 root 为根的子树中,答案为 LCA(u, v);
- 若 u 和 v 其一以 root 为根的子树中,则u 到 v 的路径跨过 root,答案为 root;
- 若 u 和 v 都不在以 root 为根的子树中,若 LCA(u, root) = LCA(v, root),则答案为 LCA(u, v);否则为 LCA(u, root) 和 LCA(v, root) 中深度较大者。
- u 和 v 其一在 root 所在子树
不妨设 v 在 root 所在子树。若 u 到 v 的路径跨过 root,即 v 在以 root 为根的子树中,则答案为 root;否则答案为 LCA(root, v)。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
const int MAXN = 100010;
int n, m, root, dep[MAXN], f[MAXN][20], subtr[MAXN];
char opt[10];
std::vector<int> son[MAXN];
void dfs(int u, int fa) {
if (fa == 1) subtr[u] = u;
else subtr[u] = subtr[fa];
dep[u] = dep[fa] + 1;
f[u][0] = fa;
for (int i = 0; i < 19; ++i) {
f[u][i + 1] = f[f[u][i]][i];
}
for (auto v : son[u]) {
if (v == fa) continue;
dfs(v, u);
}
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) std::swap(x, y);
for (int i = 19; i >= 0; --i) {
if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return x;
}
for (int i = 19; i >= 0; --i) {
if (f[x][i] != f[y][i]) {
x = f[x][i];
y = f[y][i];
}
}
x = f[x][0];
return x;
}
int main() {
freopen("dynamic.in", "r", stdin);
freopen("dynamic.out", "w", stdout);
while (~scanf("%d", &n) && n) {
root = 1;
for (int i = 1; i <= n; ++i) {
son[i].clear();
memset(f[i], 0, sizeof(f[i]));
}
int u, v;
for (int i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
son[u].push_back(v);
son[v].push_back(u);
}
dfs(1, 0);
scanf("%d", &m);
while (m--) {
scanf("%s", opt);
if (opt[0] == '?') {
scanf("%d%d", &u, &v);
if (root == 1) {
printf("%d\n", LCA(u, v));
continue;
}
int x = subtr[u], y = subtr[v], t = subtr[root];
if (x != t && y != t) {
printf("%d\n", LCA(u, v));
} else if (x == t && y == t) {
int a = LCA(u, root), b = LCA(v, root);
if (a == root && b == root) printf("%d\n", LCA(u, v));
else if (a != root && b != root) {
if (a == b) printf("%d\n", LCA(u, v));
else printf("%d\n", dep[a] > dep[b] ? a : b);
}
else printf("%d\n", root);
} else {
if (x == t) {
std::swap(x, y);
std::swap(u, v);
}
int temp = LCA(v, root);
if (temp == root) printf("%d\n", root);
else printf("%d\n", temp);
}
} else {
scanf("%d", &u);
root = u;
}
}
}
return 0;
}