풀이
이번엔 naive가 아닌 풀이!
이전의 naive한 풀이에서, 우리는 최악의 경우에 n번의 노드를 하나씩하나씩 올라가야했다.
하지만 이를 log(n)으로 줄일 수 있다!
pnt[i][j] = i번 노드의 2^j번째 조상
으로 두고 풀면 된다.
트리의 깊이를 구할 때 2^j번째 조상을 구해두자.
tmp = anc[i][j-1]일 때, anc[i][j]는 anc[tmp][j-1]과 같다.
즉, i의 2^j번째 조상은 2^(j-1)번째 조상의 2^(j-1)번째 조상과 같다는 의미이다.
i의 2^3=8번째 조상은 2^2=4번째 조상의 2^2=4번째 조상과 같다.
naive한 코드에서 2^j를 도는 동작만 추가해주면 어렵지 않게(?) 훨씬 빠르게(!) 구현할 수 있다.
코드
#include <stdio.h>
#include <algorithm>
#include <vector>
using namespace std;
const int n_ = 1e5 + 5;
const int d_ = 17;
int n, m, d;
int dph[n_], act[n_][d_];
vector<int> gph[n_];
inline void dfs(int now, int cnt) {
dph[now] = cnt++;
for (int i = 1; i <= d; i++)
act[now][i] = act[act[now][i - 1]][i - 1];
for (auto nxt : gph[now]) if (!dph[nxt])
act[nxt][0] = now, dfs(nxt, cnt);
}
int main() {
int i, a, b;
scanf("%d", &n);
for (d = 1; (1 << d) <= n; d++); d--;
while (--n) {
scanf("%d %d", &a, &b);
gph[a].push_back(b);
gph[b].push_back(a);
}
dfs(1, 1);
scanf("%d", &m);
while (m--) {
scanf("%d %d", &a, &b);
if (dph[a] < dph[b]) swap(a, b);
for (i = d; i >= 0; i--) if (dph[b] <= dph[act[a][i]])
a = act[a][i];
if (a == b) {
printf("%d\n", a);
continue;
}
for (i = d; i >= 0; i--) if (act[a][i] != act[b][i])
a = act[a][i], b = act[b][i];
printf("%d\n", act[a][0]);
}
return 0;
}
아무말
백준, 백준 온라인 저지, BOJ, Baekjoon Online Judge, C, C++, 씨, 씨쁠쁠, JAVA, algorithm, 자바, 알고리즘, 자료구조, 문제, 문제 풀이, 풀이