模板 - 图论 - 树 - 最近公共祖先
令 $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]; }