※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 15480번 문제인 LCA와 쿼리이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/15480
15480번: LCA와 쿼리
첫째 줄에 정점의 개수 N(1 ≤ N ≤ 100,000)이 주어진다. 둘째 줄부터 N-1개의 줄에는 트리 T의 간선 정보 u와 v가 주어지다. u와 v는 트리의 간선을 나타내는 두 정점이다. 다음 줄에는 쿼리의 개수 M(
www.acmicpc.net
임의의 노드를 루트로 잡은 rooted tree에서, 어떤 노드를 루트로 잡았을 때의 임의의 두 노드 사이의 LCA를 찾아내는 문제이다.
힌트 - 트리 위에서 임의로 세 점을 잡아서, 두 점끼리의 LCA를 각각 구했을 때 어떠한 특징이 있는지 관찰해보자. 이를 통해 문제를 해결할 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> G[100001];
int level[100001];
int T[100001][17];
void Tinit(int N) {
for (int k = 1; k < 17; k++) {
for (int i = 1; i <= N; i++) {
T[i][k] = T[T[i][k - 1]][k - 1];
}
}
}
void dfs(int current, int parent, int lv) {
level[current] = lv++;
for (auto node : G[current]) {
if (node == parent) T[current][0] = parent;
else dfs(node, current, lv);
}
}
int lca(int x, int y) {
if (level[x] != level[y]) {
if (level[x] < level[y]) swap(x, y);
int diff = level[x] - level[y];
int temp = 0;
while (diff > 0) {
if (diff & 1) x = T[x][temp];
diff >>= 1;
temp++;
}
}
if (x != y) {
for (int k = 16; k >= 0; k--) {
if (T[x][k] == T[y][k]) continue;
x = T[x][k], y = T[y][k];
}
x = T[x][0], y = T[y][0];
}
return x;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
int N; cin >> N;
for (int i = 1; i < N; i++) {
int x, y; cin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
T[1][0] = 1;
dfs(1, 1, 0);
Tinit(N);
int Q; cin >> Q;
while (Q--) {
int r, x, y; cin >> r >> x >> y;
int rx = lca(r, x), ry = lca(r, y), xy = lca(x, y);
if (rx == ry) cout << xy << '\n';
else if (xy == rx) cout << ry << '\n';
else cout << rx << '\n'; // xy == ry
}
}
728x90
'BOJ' 카테고리의 다른 글
[BOJ 13913 // C++] 숨바꼭질 4 (0) | 2021.07.22 |
---|---|
[BOJ 1647 // C++] 도시 분할 계획 (0) | 2021.07.21 |
[BOJ 3351 // C++] 삼각 분할 (0) | 2021.07.19 |
[BOJ 2570 // C++] 비숍2 (0) | 2021.07.18 |
[BOJ 5398 // C++] 틀렸습니다 (0) | 2021.07.17 |