Skip to content

最近公共祖先LCA

约 74 个字 124 行代码 预计阅读时间 2 分钟

树链剖分

使用两边 dfs 进行树链剖分,让两个节点跳转后位于同一链条,层次低的就是最近公共祖先

C++
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define INF 0x3f3f3f3f
#define LL long long
const int MAXN = 5e5 + 5;
const double EPS = 1e-9;
vector<int> G[MAXN];
int fa[MAXN], dep[MAXN], son[MAXN], sz[MAXN];
int top[MAXN];
void dfs1(int u, int father)
{
    fa[u] = father;
    dep[u] = dep[father] + 1;
    sz[u] = 1;
    for (int v : G[u]) {
        if (v == father) continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) {
            son[u] = v;
        }
    }
}
void dfs2(int u, int t)
{
    top[u] = t;
    if (!son[u]) return;
    dfs2(son[u], t);
    for (int v : G[u]) {
        if (v == fa[u] || v == son[u]) continue;
        dfs2(v, v);
    }
}
int lca(int u, int v)
{
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) {
            swap(u, v);
        }
        u = fa[top[u]];
    }
    return dep[u] < dep[v] ? u : v;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m, s;
    cin >> n >> m >> s;
    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    int a, b;
    dfs1(s, s);
    dfs2(s, s);
    while (m--) {
        cin >> a >> b;
        cout << lca(a, b) << endl;
    }
    return 0;
}

倍增

C++
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define INF 0x3f3f3f3f3f3f3f3f
#define LL long long
const int MAXN = 1e5 + 5;
const double EPS = 1e-9;
int n, m, s, a, b;

vector<vector<int>> g;
vector<int> dep;
vector<vector<int>> fa;
void dfs(int u, int father)
{
    dep[u] = dep[father] + 1;
    fa[u][0] = father;
    for (int i = 1; i <= 22; i++) {
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    }
    for (auto ele : g[u]) {
        if (ele == father) continue;
        dfs(ele, u);
    }
}
int lca(int u, int v)
{
    if (dep[u] < dep[v]) swap(u, v);
    for (int i = 22; i >= 0; i--) {
        if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
    }
    if (u == v) return u;
    for (int i = 22; i >= 0; i--) {
        if (fa[u][i] != fa[v][i]) {
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    return fa[u][0];
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m >> s;
    g.assign(n + 1, vector<int>());
    dep.resize(n + 1);
    fa.assign(n + 1, vector<int>(23, 0));
    for (int i = 1; i < n; i++) {
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(s, 0);
    while (m--) {
        cin >> a >> b;
        cout << lca(a, b) << endl;
    }
    return 0;
}