$O(n+m\lg n)$
LCA를 구현하자. sparse table을 이용한다.
#include<stdio.h> #include<vector> #include<algorithm> using namespace std; const int MAX_N = 100000, LGN = 16; int n, m; int dp[MAX_N + 1][LGN + 1], lv[MAX_N + 1]; bool ck[MAX_N + 1]; vector<int> adj[MAX_N + 1]; void dfs(int h) { ck[h] = true; for (auto it : adj[h]) { if (ck[it]) continue; lv[it] = lv[h] + 1; dp[it][0] = h; for (int i = 1; i <= LGN; i++) dp[it][i] = dp[dp[it][i - 1]][i - 1]; dfs(it); } } int lca(int x, int y) { if (lv[x] < lv[y]) swap(x, y); for (int i = LGN; i >= 0; i--) if (1 << i <= lv[x] - lv[y]) x = dp[x][i]; if (x == y) return x; for (int i = LGN; i >= 0; i--) if (dp[x][i] != dp[y][i]) x = dp[x][i], y = dp[y][i]; return dp[x][0]; } int main() { scanf("%d", &n); for (int i = 0; i < n - 1; i++) { int a, b; scanf("%d %d", &a, &b); adj[a].push_back(b); adj[b].push_back(a); } dfs(1); scanf("%d", &m); for (int i = 0; i < m; i++) { int a, b; scanf("%d %d", &a, &b); printf("%d\n", lca(a, b)); } return 0; }
dfs 만드는 것 까진 이해했고, lca에서 같은 depth 찾아가는 것 까진 이해했는데 lca 마지막 부분에
답글삭제for (int i = LGN; i >= 0; i--)
if (dp[x][i] != dp[y][i])
x = dp[x][i], y = dp[y][i];
return dp[x][0];
이부분말인데,
같은 깊이의 x,y 노드에 대해서 2^i 번째 부모가 다르다면 그 밑에 있는 부모는 무조건 lca 가 안 된다는 가정 하에 진행되는 것 같은데...
이 부분을 증명해줄 수 있을까?
이 알고리즘은 트리에서 작동하기 때문에 x가 공통조상이라면 x의 조상노드들은 모두 공통조상임. x가 공통조상이 아닐 때 하위 노드들 중 공통 조상이 존재한다면 x역시 공통 조상이어야 하므로 모순이 생김. 따라서 해당 노드의 하위노드들 중엔 공통조상이 없다는 것을 알 수 있음.
답글삭제