模板 - 图论 - 树 - 最近公共祖先

令 $f[i][j]$ 表示 $i$ 的 $2^j$ 辈祖先, $f[i][0]$ 就表示 $i$ 的父节点。

可以得到状态转移方程 $f[i][j]=f[f[i][j-1]][j-1]$ 。当没有 $2^j$ 辈祖先时 $f[i][j]=0$ 

一遍 DFS 计算即可

void dfs(int u, int father) {
    dep[u] = dep[father] + 1;  // dep[x] 表示 x 的深度,在查询时会用到
    for (int i = 0; i <= 19; i++)
        f[u][i + 1] = f[f[u][i]][i];  // 预处理
    for (int i = first[u]; i; i = next[i]) {/ 链式前向星
        int v = go[i];
        if (v == father)
            continue;
        f[v][0] = u;  // f[v][0] 表示 v 的父亲
        dfs(v, u);
    }
}

查询

先往上2进制跳到同深度,再2进制一起往上跳。

int lca(int x, int y) {
    if (dep[x] < dep[y])
        swap(x, y);  // 步骤 1
    for (int i = 20; i >= 0; i--) {   // 步骤 2
        if (dep[f[x][i]] >= dep[y])
            x = f[x][i];
        if (x == y)
            return x;
    }
    for (int i = 20; i >= 0; i--)  // 步骤 3
        if (f[x][i] != f[y][i]) {
            x = f[x][i];
            y = f[y][i];
        }
    return f[x][0];
}

 

posted @ 2019-03-04 20:13  韵意  阅读(126)  评论(0编辑  收藏  举报