51nod2599 最近公共祖先LCA

91 阅读1分钟

题面:给定一颗n个节点的树,根节点编号为1,有Q组询问,每次给定一对节点编号(x,y),求(x,y)的最近公共祖先。

范围:1 <= n <= 1E3; 1 <= Q <= 1E3

分析:求LCA有多种方法,这里用的是倍增法,预处理时间O(nlogn),单次查询时间O(logn),支持在线。

#include <bits/stdc++.h>
const int N = 1005;
int dep[N], fa[N][11];
std::vector<int> adj[N];
void dfs(int x, int p) {
    fa[x][0] = p;
    dep[x] = dep[p] + 1;
    for (int i = 1; i <= 10; i++) {
        fa[x][i] = fa[fa[x][i-1]][i-1];
    }
    for (auto i : adj[x]) if (i != p) {
        dfs(i, x);
    }
}
int lca(int x, int y) {
    if (dep[x] < dep[y]) std::swap(x, y);
    for (int i = 10; i >= 0; i--) {
        if (dep[fa[x][i]] >= dep[y]) {
            x = fa[x][i];
        }
    }
    if (x == y) return x;
    for (int i = 10; i >= 0; i--) {
        if (fa[x][i] != fa[y][i]) {
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    return fa[x][0];
}
void solve() {
    int n;
    std::cin >> n;
    for (int i = 1; i < n; i++) {
        int u, v;
        std::cin >> u >> v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    dfs(1, 1);

    int Q;
    std::cin >> Q;
    while (Q--) {
        int a, b;
        std::cin >> a >> b;
        std::cout << lca(a,b) << "\n";
    }
}
int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

标签:倍增