반응형
< 풀이 >
직관대로 풀면 되는 문제. 단 case 처리 시 조금 까다로운 면이 있다. 외심 후보 3개를 두 점의 중점으로 고르고 나머지 한 점에서의 거리와 두 점에서의 거리가 같은 지 비교하면 끝.
만약 3개의 점 중 2개의 점이 동일한 경우에는 한번만 get_center해주면 됨. 3개의 점이 다 동일한 경우에는 그냥 그 점을 출력.
< 소스 코드 >
#include <bits/stdc++.h>
using namespace std;
#define INF 987654321
typedef long long ll;
typedef pair<int, int> ii;
typedef tuple<int, int, int> iii;
#define swap(a,b){int t=a; a=b; b=t;}
#define N_MAX 100010
int N, Q;
vector<int> graph[N_MAX];
// depth :: 노드의 깊이(레벨)
// ac[x][y] :: x의 2^y번째 조상을 의미 : sparse table
int depth[N_MAX];
int ac[N_MAX][25];
int max_level = (int)floor(log2(N_MAX));
void DFS(int here, int parent){
depth[here] = depth[parent] + 1;
// 나의 1번째 조상은 부모
ac[here][0] = parent;
for(int i=1; i<=max_level;i++){
int prev = ac[here][i-1];
ac[here][i] = ac[prev][i-1];
}
int len = graph[here].size();
for (int i=0; i<len; i++){
int next = graph[here][i];
if (next == parent) continue;
DFS(next, here);
}
}
int get_lca(int c, int d){
// lca를 구한다
// 1) 같은 depth까지 끌어 올린다
if (depth[c] != depth[d]){
if (depth[c] > depth[d]) swap(c,d); // 항상 depth d가 더 크게
for(int i=max_level;i>=0;i--){
if(depth[c] <= depth[ac[d][i]]){
d = ac[d][i];
}
}
}
int lca = c;
// 2) 같은 depth라면 lca를 찾는다
if (c != d){
for(int i=max_level; i>=0; i--){
if (ac[c][i] != ac[d][i]){
c = ac[c][i];
d = ac[d][i];
}
lca = ac[c][i];
}
}
return lca;
}
int get_distance(int a, int b){
if (a == -1 || b == -1) return -1;
int lca = get_lca(a, b);
return depth[a] + depth[b] - 2* depth[lca]+1;
}
// 외심을 구하는 함수
int get_center(int a, int b){
if (a > b) { // swap : 항상 a <= b가 되도록
swap(a,b);
}
int lca = get_lca(a, b);
int total_dist = depth[a] + depth[b] - 2* depth[lca]+1;
if ((total_dist % 2) == 0) return -1; // 짝수 distance는 있을 수 없다
int k = (total_dist + 1) / 2;
int k_th = 0;
// trace number + k를 구한다.(k번째는 중앙점)
if (depth[a]-depth[lca] + 1 >= k){ // c~lca 사이에 k가 있다
k--;
k_th = a;
for(int i=max_level; i>=0; i--){
if((1 << i) <= k){ // 2^i < k이면
k -= (1 << i);
k_th = ac[k_th][i];
}
}
}
else { // lca ~ d 사이에 k가 있다
k_th = b;
// 전체 경로 길이 - k값
k = depth[a] + depth[b] - 2*depth[lca] - (k - 1);
for(int i=max_level;i>=0;i--){
if((1 << i) <= k){ // 2^i < k이면
k -= (1 << i);
k_th = ac[k_th][i]; // d에서부터 위로 올린다
}
}
}
return k_th;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> N;
for(int i=1; i<N;i++){
int a, b;
cin >> a >> b;
graph[a].push_back(b);
graph[b].push_back(a);
}
// 1번 root의 depth가 0이 되도록 하기 위해서임.
depth[0] = -1;
DFS(1,0);
cin >> Q;
while(Q--){
int a, b, c;
cin >> a >> b >> c;
if (a == b && b == c) {
cout << a << '\n';
}
else if (a == b || b == c || c == a) {
int small = min(a, b); small = min(small, c); // 두 점 중 작은 게 a
int big = max(b, a); big = max(big, c); // 두 점 중 큰 게 b
cout << get_center(small, big) << '\n';
}
else { // a != b != c
int ab_center = get_center(a,b);
int bc_center = get_center(b,c);
int ca_center = get_center(c,a);
// ab ~ center 거리랑 c랑 ~ center 거리
if (get_distance(a,ab_center) == get_distance(c,ab_center)){
cout << ab_center << '\n';
}
else if (get_distance(b,bc_center) == get_distance(a,bc_center)){
cout << bc_center << '\n';
}
else if (get_distance(c,ca_center) == get_distance(b,ca_center)){
cout << ca_center << '\n';
}
else {
cout << -1 << '\n';
}
}
}
return 0;
}
반응형
'컴퓨터 사이언스 > BOJ' 카테고리의 다른 글
[c++] 백준 #2904 수학은 너무 쉬워 (190830) (0) | 2019.10.08 |
---|---|
[c++] 백준 #11585 속타는 저녁메뉴 (190830) (0) | 2019.10.08 |
[c++] 백준 #17398 통신망 분할 (190826) (0) | 2019.10.08 |
[c++] 백준 #1987 알파벳 (190823) (0) | 2019.10.08 |
[c++] 백준 #1561 놀이공원 (190822) (0) | 2019.10.08 |
댓글