LCA
LCA - Least Common Ancestors 一颗树上两个节点的最近公共祖先
求解这个问题, 有这样一种方法
在两点的路径上找深度最小的点
先第一遍DFS一颗树, 得到一个按节点访问顺序记录的序列seq[NODE_NUMBER]
void Dfs(int u, int fa, int dep) { seq[++cnt] = u; first[u] = cnt; depth[cnt] = dep; int len = edge[u].size(); for(int i = 0; i < len; i++) { int v = edge[u][i].v; if(v != fa) { dis[v] = dis[u] + edge[u][i].w; Dfs(v, u, dep+1); seq[++cnt] = u; depth[cnt] = dep; } } }
同时记录每个节点第一次访问时 在这个序列中的位置 first[u]
这样, 询问两个节点u, v时, 路径就是这两个节点第一次出现位置中间访问的一段序列, seq[first[u], first[v]]
只要找出这段序列中深度最小的点就可以了, 这是一个RMQ问题, 可以提前预处理, 可以用ST算法来解决
void RMQ_Init(int n) { for(int i = 1; i <= n; i++) { dp[i][0] = i; } for(int j = 1; (1 << j) <= n; j++) { for(int i = 1; i + (1 << j) - 1 <= n; i++) { int a = dp[i][j-1], b = dp[i + (1 << (j-1))][j-1]; dp[i][j] = depth[a] < depth[b] ? a : b; } } } int RMQ_Query(int l, int r) { int k = 0; while((1 << k) <= r - l + 1) k++; int a = dp[l][k], b = dp[r-(1<<k)+1][k]; return depth[a] < depth[b] ? a : b; }
最终查询
int LCA(int u, int v) { int a = first[u], b = first[v]; if(a > b) a ^= b, b ^= a, a ^= b; int res = RMQ_Query(a, b); return seq1[res]; }