1부터 N까지의 도시를 연결하는 N-1개의 도로가 주어지고
서로 다른 두 도시 D, E가 주어지면 D와 E를 연결하는 도로 중
가장 짧은 것의 길이와 긴 것의 길이를 구한다.
이때 모든 서로 다른 두 도시간 경로는 한 개만 존재한다.
⇒ 주어진 그래프가 트리이다.
LCA문제임은 빠르게 파악할 수 있었다.
다만 공통조상뿐 아니라 공통조상까지의 도로의 길이 중 최댓값/최솟값도 알아야 했고
여기저기 헷갈린 탓인지 여러 차례 틀려서 힘들었다ㅠ
1. Get P
먼저 각 도시의 1, 2, 4, 8, ...번째 조상을 조사한다.
1을 root로 하여 BFS로 탐색하고, 조상을 탐색하며 도로 길이의 최소/최대를 구한다.
P[ i ][ k ]
r = 도시 i의 $2^{\mathrm{k}}$번째 조상
mn = i부터 조상까지의 최소 도로 길이
mx = i부터 조상까지의 최대 도로 길이
Q.push(1), dep[1] = 1;
while (!Q.empty()) {
int prv = Q.front(); Q.pop();
for (road r : R[prv]) {
if (dep[r.v]) continue;
int cur = r.v; Q.push(cur);
dep[cur] = dep[prv] + 1;
P[cur][0] = { prv, r.c, r.c };
for (int k = 0; k < 17; ++k) {
if (!P[P[cur][k].v][k].v) break;
P[cur][k + 1].v = P[P[cur][k].v][k].v;
P[cur][k + 1].mn = min(P[cur][k].mn, P[P[cur][k].v][k].mn);
P[cur][k + 1].mx = max(P[cur][k].mx, P[P[cur][k].v][k].mx);
}
}
}
- DFS로 해도 된다. 그러나 큐를 써도 BFS가 더 빨랐다.
- 트리만 구축하고 for문으로 돌려도 된다. 그러나 BFS내부에서 처리하는 게 더 빨랐다.
2. Get ANS
이제 입력을 받으며 도시 d, e에 대한 답 minn, maxx를 구한다.
먼저 두 도시의 depth가 다르면 같게 해주면서 minn, maxx를 업데이트하고
두 도시의 depth가 동일해지면 LCA를 찾아 minn, maxx를 업데이트한다.
int minn = INF;
int maxx = 0;
if (dep[d] > dep[e]) swap(d, e);
// 1. Make Depth Same
for (int k = 17; k >= 0; --k) {
if (dep[e] - dep[d] >= (1 << k)) {
minn = min(minn, P[e][k].mn);
maxx = max(maxx, P[e][k].mx);
e = P[e][k].v;
}
}
// 2. Find LCA
if (d != e) {
for (int k = 17; k >= 0; --k) {
if (P[d][k].v == P[e][k].v) continue;
minn = min(minn, min(P[d][k].mn, P[e][k].mn));
maxx = max(maxx, max(P[d][k].mx, P[e][k].mx));
d = P[d][k].v, e = P[e][k].v;
}
minn = min(minn, min(P[d][0].mn, P[e][0].mn));
maxx = max(maxx, max(P[d][0].mx, P[e][0].mx));
}
- minn, maxx먼저 업데이트한 뒤에 d, e를 업데이트 해야 한다.
- 2의(line 15-24)
for문(line 16-21)에서는 d의 부모와 e의 부모가 다를 때만 업데이트하므로
for문이 끝난 후(line 22-23) minn과 maxx를 한 번 더 업데이트 해야 한다. - example.
아래 오른쪽 그림에서 d=9 e=2이면
line 6-12: d=6 e=2
line 16-21: d=5 e=3 이므로
line 22-23 에서 minn, maxx를 한 번 더 업데이트 해줘야 한다.
전체 코드
더보기
R[ i ] 도시 i의 도로 정보
P[ i ][ k ] 도시 i의 $2^{\mathrm{k}}$번째 조상에 대해 조사
dep[ i ] 도시 i의 depth (dep[1]=1 기준)
#include <cstdio>
#include <queue>
#include <algorithm>
#define INF 1000001
using namespace std;
struct road{
int v, c;
};
vector<road> R[100001];
struct parent {
int v, mn = INF, mx = 0;
};
parent P[100001][18];
int dep[100001];
queue<int> Q;
void GetP() {
Q.push(1), dep[1] = 1;
while (!Q.empty()) {
int prv = Q.front(); Q.pop();
for (road r : R[prv]) {
if (dep[r.v]) continue;
int cur = r.v; Q.push(cur);
dep[cur] = dep[prv] + 1;
P[cur][0] = { prv, r.c, r.c };
for (int k = 0; k < 17; ++k) {
if (!P[P[cur][k].v][k].v) break;
P[cur][k + 1].v = P[P[cur][k].v][k].v;
P[cur][k + 1].mn = min(P[cur][k].mn, P[P[cur][k].v][k].mn);
P[cur][k + 1].mx = max(P[cur][k].mx, P[P[cur][k].v][k].mx);
}
}
}
}
int main() {
int N, K, a, b, c, d, e;
scanf("%d", &N);
for (int i = 1; i < N; ++i) {
scanf("%d%d%d", &a, &b, &c);
R[a].push_back({ b,c }); R[b].push_back({ a,c });
}
GetP();
scanf("%d", &K);
while (K--) {
scanf("%d%d", &d, &e);
int minn = INF;
int maxx = 0;
if (dep[d] > dep[e]) swap(d, e);
for (int k = 17; k >= 0; --k) {
if (dep[e] - dep[d] >= (1 << k)) {
minn = min(minn, P[e][k].mn);
maxx = max(maxx, P[e][k].mx);
e = P[e][k].v;
}
}
if (d != e) {
for (int k = 17; k >= 0; --k) {
if (P[d][k].v == P[e][k].v) continue;
minn = min(minn, min(P[d][k].mn, P[e][k].mn));
maxx = max(maxx, max(P[d][k].mx, P[e][k].mx));
d = P[d][k].v, e = P[e][k].v;
}
minn = min(minn, min(P[d][0].mn, P[e][0].mn));
maxx = max(maxx, max(P[d][0].mx, P[e][0].mx));
}
printf("%d %d\n", minn, maxx);
}
return 0;
}
/*
12
1 5 20 1 3 10 3 2 100 3 4 200 2 12 60
5 6 40 6 7 50 6 8 70 8 9 200 8 11 110 9 10 120
10
10 6
11 3
*/
'Probelm Solving > BOJ' 카테고리의 다른 글
BOJ1949 우수 마을 (0) | 2021.06.10 |
---|---|
BOJ1014 컨닝 (0) | 2021.05.19 |
BOJ1086 박성원 (0) | 2021.04.21 |
BOJ13141 Ignition (0) | 2021.03.17 |
BOJ10714 케이크 자르기 2 (0) | 2021.01.30 |
댓글