11438 : LCA2

풀이

이번엔 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, 자바, 알고리즘, 자료구조, 문제, 문제 풀이, 풀이

wookje.kwon's profile image

wookje.kwon

2017-04-11 11:48

Read more posts by this author