給定 N 對父子關係(構成一棵樹),所有人共享一個公共祖先(根節點)。需回答 M 個查詢:任意兩人的所有共同祖先中,輩分最低(即最近)的是誰?
數據範圍:N, M ≤ 10^5,需高效演算法。
Tarjan 演算法結合 深度優先搜索 (DFS) 與 並查集,在一次遍歷中解決所有查詢,時間複雜度 O(N + M)。
若節點 u、v 分別位於節點 t 的不同子樹中,則 t 為 u、v 的最近公共祖先。若一節點是另一節點的祖先,則該祖先節點即為 LCA。
father[u] = u,標記 ancestor[u] = u。Union(u, v),並更新 ancestor[Find(u)] = u。LCA(u, x) = ancestor[Find(x)]。以樹結構為例,分步驟展示並查集合併過程與祖先標記更新:

遍歷順序:1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 ... 每完成一個子樹合併,該子樹內任意兩節點的 LCA 即為當前根。
const int MAXN = 1e5 + 5;
vector<int> tree[MAXN];
vector<pair<int, int>> query[MAXN]; // {對方節點, 查詢編號}
int ancestor[MAXN], father[MAXN], ans[MAXN];
bool visited[MAXN];
int Find(int x) { return x == father[x] ? x : father[x] = Find(father[x]); }
void Union(int x, int y) { father[Find(x)] = Find(y); }
void Tarjan(int u) {
ancestor[u] = father[u] = u;
for (int v : tree[u]) {
Tarjan(v);
Union(u, v);
ancestor[Find(u)] = u;
}
visited[u] = true;
for (auto [v, idx] : query[u]) {
if (visited[v]) ans[idx] = ancestor[Find(v)];
}
}