vector<int> tree[MAX];// 以鄰接表形式儲存 int dep[MAX]; int fas[MAX];
namespace M1 { voiddfs(int x, int fa){ if (fa != -1) { dep[x] = dep[fa] + 1; } fas[x] = fa; for (int i = 0; i < tree[x].size(); i++) { if (fas[tree[x].at(i)] == -2) M1::dfs(tree[x].at(i), x); } }
intsolve(int a, int b){ while (1) { if (a == b) { return a; } elseif (fas[a] == fas[b]) { return fas[a]; } elseif (fas[b] == a) { return a; } elseif (fas[a] == b) { return b; } int da = dep[a], db = dep[b]; int delta = abs(da - db); if (da > db) { for (int i = 0; i < delta; i++) { a = fas[a]; da = dep[a]; } } elseif (da < db) { for (int i = 0; i < delta; i++) { b = fas[b]; db = dep[b]; } } else { a = fas[a]; da = dep[a]; } } return-1; } }// namespace M1
bool first = true;
intLCA(int a, int b, int r){ if (first) { M1::dfs(r, -1); first = false; } int res; res = M1::solve(a, b); return res; }
intmain(int argc, char *argv[]){ int m, n, s; cin >> m >> n >> s; for (int i = 0; i < MAX; i++) { dep[i] = 0; fas[i] = -2; } for (int i = 1; i < n; i++) { int x, y; cin >> x >> y; tree[x].push_back(y); tree[y].push_back(x); } dep[s] = 0; fas[s] = -1; for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; int res = LCA(a, b, s); cout << res << endl; } return0; }
注意這道題目的資料輸入,x y表示x 結點和 y
結點之間有一條直接連線的邊(資料保證可以構成樹)。
所以需要用鄰接表的形式,表示多叉樹。
voiddfs(int x, int fa){ // x 是當前節點,fa 是它的父節點 if (fa != -1) { dep[x] = dep[fa] + 1; // x 的深度就是它的父節點加一,這很好理解 } fas[x][0] = fa; // x 節點的第一個父節點是 fa for (int i = 1; (1 << i) <= dep[x]; i++) { // 迴圈直至 2^i 大於當前節點深度,即完成當前節點到樹根的所有可跳轉到的節點的預處理工作 fas[x][i] = fas[fas[x][i - 1]][i - 1]; // 這一步是演算法的精髓 // 得到狀態轉移方程,動態規劃計算 // 意思是x的2^i祖先等於x的2^(i-1)祖先的2^(i-1)祖先 } for (int i = 0; i < tree[x].size(); i++) { if (tree[x].at(i) != fa) dfs(tree[x].at(i), x); // 鄰接表儲存當前節點所有相連的節點,只要節點不是它的父節點,即節點是它的子節點,就進行下一步遞迴 } } // 深度優先搜尋來預處理一下
intsolve(int a, int b){ if (dep[b] > dep[a]) swap(a, b); // 確保 a 的深度更深,避免冗餘的判斷 while (dep[a] > dep[b]) { a = fas[a][lg2(dep[a] - dep[b]) - 1]; // a 向上跳,跳至兩節點同級 } if (a == b) return a; // 若此時兩節點相遇,就可以直接返回。否則兩節點還需再次向上跳。 for (int i = lg2(dep[a]); i >= 0; i--) { if (fas[a][i] != fas[b][i]) { a = fas[a][i]; b = fas[b][i]; } } // 從可跳到的最高處向下列舉,得到 LCA return fas[a][0]; // 返回答案 }
intLCA(int a, int b, int r){ if (first) { dep[r] = 0; fas[r][0] = -1; dfs(r, -1); first = false; } int res; res = solve(a, b); return res; }
intmain(int argc, char *argv[]){ int m, n, s; cin >> m >> n >> s; for (int i = 0; i < MAX; i++) { dep[i] = 0; for (int j = 0; j < MUL_MAX; j++) fas[i][j] = -2; } // 陣列初始化 for (int i = 1; i < n; i++) { int x, y; cin >> x >> y; tree[x].push_back(y); tree[y].push_back(x); // 鄰接表存入資料 } for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; int res = LCA(a, b, s); cout << res << endl; } return0; }