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;
}
posted @ 2022-08-13 10:11  东方澂  阅读(19)  评论(0编辑  收藏  举报