문제
https://www.acmicpc.net/problem/11438
시간 제한 | 메모리 제한 | solved.ac 티어 |
1.5초 | 256MB | 플래티넘 5 |
풀이
밀린 문제 정리하기. LCA 알고리즘 편이다. 저번 문제에서는 O(n) LCA 로 풀 수 있는 문제였지만, 이 문제는 정말 불가능한 문제이다. 겸허히 O(log(N)) LCA를 사용해야 한다. O(n) LCA의 문제는 부모 노드로 이동하기 위해, 본인의 조상 노드를 하나씩 움직여야 하기에 선형시간이 걸리지만, 높이가 클 수록 비효율적일 것이다. 여기서 하나의 의문이 발생한다. 굳이 하나씩 다 이동해야 하는가?
이를 해결하기위해 희소테이블을 사용한다. 트리의 데이터를 저장할때, 본인의 부모노드만 저장했지만, 희소테이블을 적용하여, i번째 노드의 2^0번째 부모, 2^1번째 부모, 2^2번째 부모....2^K번째 부모(K는 배열의 길이)를 저장한다. 이제 우리는 이 정보를 이용해 더 빠르게 부모노드로 이동할 수 있다. 어떤 노드의 163번째 조상을 알고 싶다고 하자. 원래라면 우리는 일일이 163번을 이동해야하지만, 163을 분해하면 163 = 128 + 32 + 2 + 1 = 2^7 + 2^5 + 2^1 + 2^0 임을 알 수 있다. 우리는 이러한 값들을 모두 저장해놨었기 때문에 4번의 이동으로 조상의 정보를 알 수 있다. 이를 적용한 것이 O(log(N)) LCA이다.
코드
#include <bits/stdc++.h>
#define endl '\n'
using namespace std;
#define MAX_A 20 // log(max(n)) = log(100k) = 17이니 여유롭게 20으로 설정
int n,m;
vector<vector<int>> tree, graph;
vector<int> depths;
vector<pair<int,int>> query;
void make_tree(int st, int p, int h) {
tree[st][0] = p, depths[st] = h;
for(int g : graph[st]) {
if (g == p) continue;
make_tree(g, st, h+1);
}
}
void make_ancestor() {
for (int ancestor = 1; ancestor <= MAX_A; ancestor++) {
for (int node = 1; node <= n; node++) {
tree[node][ancestor] = tree[tree[node][ancestor - 1]][ancestor - 1];
}
}
}
void init(){
make_tree(1, 0, 1);
make_ancestor();
}
void input(){
int a, b;
cin >> n;
graph.resize(n + 1);
tree.resize(n + 1, vector<int>(MAX_A + 1));
depths.resize(n + 1, -1);
for (int i = 1; i < n; i++){
cin >> a >> b;
graph[a].push_back(b);
graph[b].push_back(a);
}
cin >> m;
query.resize(m);
for(auto& [x, y] : query) {
cin >> x >> y;
}
init();
}
void sol() {
for(auto& [target, goal] : query) {
// target노드를 goal노드의 높이로 끌어올린다.
if (depths[target] < depths[goal]){
swap(target, goal);
}
int dh = depths[target] - depths[goal];
for (int i = MAX_A; i >= 0 && dh; i--) {
if (dh >= (1 << i)) {
target = tree[target][i];
dh -= (1 << i);
}
}
if (target == goal){
cout << goal << endl;
}
else {
for (int i = MAX_A; i >= 0; i--) {
if (tree[target][i] != 0 &&
tree[target][i] != tree[goal][i]) {
target = tree[target][i];
goal = tree[goal][i];
}
}
cout << tree[goal][0] << endl;
}
}
}
int main() {
cin.tie(0)->sync_with_stdio(0);
input();
sol();
}
'coding_test > BAEKJOON' 카테고리의 다른 글
백준 9019번 C++ 풀이 (0) | 2025.03.07 |
---|---|
백준 3584번 C++ 풀이 (0) | 2025.03.06 |
백준 11437번 C++ 풀이 (0) | 2025.03.06 |
백준 2263번 C++ 풀이 (0) | 2025.03.05 |
백준 16434번 C++ 풀이 (0) | 2025.03.02 |