LCA(最近公共祖先)Tarjan演算法模板
阿新 • • 發佈:2018-12-16
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; /** 1.dfs 2.並査集 3.鄰接表(vector、陣列模擬) */ vector < int > Tree[10009]; vector < int > query[10009]; int t, n; bool vis[10009]; int root[10009]; int ans[10009]; /** 用一個數組存放答案其實是有些不妥,只適用於每次都是不重複的兩個節點的詢問, 如果有一個節點詢問了兩次(例如a,b和a,c)就GG了,需要考慮用其他的形式存放 資料,例如鄰接表。 */ int pre[10009]; int finds(int x) { if(pre[x] == x) return x; int t = finds(pre[x]); return pre[x] = t; } void dfs(int u) { for(int i = 0; i < (int)Tree[u].size(); ++ i) { dfs(Tree[u][i]); pre[Tree[u][i]] = u; ///合併 } vis[u] = true; ///標記為已訪問 for(int i = 0; i < (int)query[u].size(); ++ i) { if(vis[query[u][i]]) { int x = finds(query[u][i]); ans[u] = x; ans[query[u][i]] = x; } } } int main() { //freopen("in.txt", "r", stdin); cin >> t; while(t--) { cin >> n; memset(vis, false, sizeof(vis)); memset(root, 0, sizeof(root)); memset(ans, 0, sizeof(ans)); for(int i = 1; i <= n; ++ i) { pre[i] = i; } for(int i = 1; i < n; ++ i) { int u, v; cin >> u >> v; Tree[u].push_back(v); root[v]++; ///計算每個節點的入度,最後找到根節點 } int a, b; cin >> a >> b; query[a].push_back(b); query[b].push_back(a); for(int i = 1; i <= n; ++ i) { if(!root[i]) ///如果是根節點的話dfs { dfs(i); } } cout << ans[a] << endl; for(int i = 1; i <= n; ++ i) { Tree[i].clear(); query[i].clear(); } } return 0; }