주어진 문제는 트리에서 세 개의 특정 정점으로부터의 거리가 같고 최소인 정점(외심)을 찾는 것이다. 주어진 입력으로 트리를 구성하고, 특정 세 정점 (A, B, C)에 대해:
이 문제는 트리의 특성과 최소 공통 조상 (Lowest Common Ancestor, LCA) 알고리즘을 활용해 풀 수 있다.
트리에서 두 정점 사이의 거리:
외심 후보 계산:
LCA 전처리:
#include <bits/stdc++.h>
using namespace std;
#define MAX 100001
// 배열 depth는 각 노드의 깊이를 저장
int nodeDepth[MAX], parent[MAX][20];
vector<int> adjacencyList[MAX];
// LCA 테이블 생성
void generateLcaTable(int currentNode, int parentNode, int depth){
nodeDepth[currentNode] = depth;
parent[currentNode][0] = parentNode;
for (int i = 1; i < 20; i++) {
parent[currentNode][i] = parent[parent[currentNode][i - 1]][i - 1];
}
// 트리를 순회하며 자식 노드 탐색
for (auto nextNode : adjacencyList[currentNode]) {
if (nextNode == parentNode) continue;
generateLcaTable(nextNode, currentNode, depth + 1);
}
}
// 두 노드의 LCA를 찾는 함수
int findLca(int node1, int node2){
if (nodeDepth[node1] < nodeDepth[node2]) swap(node1, node2);
// 깊이를 맞추기 위해 node1을 이동
for (int i = 19; i >= 0; i--) {
if (nodeDepth[node1] - nodeDepth[node2] >= (1 << i)) {
node1 = parent[node1][i];
}
}
if (node1 == node2) return node1;
// 두 노드가 같은 부모를 가질 때까지 이동
for (int i = 19; i >= 0; i--) {
if (parent[node1][i] != parent[node2][i]) {
node1 = parent[node1][i];
node2 = parent[node2][i];
}
}
return parent[node1][0];
}
// 두 노드 간의 거리 계산
int calculateDistance(int node1, int node2){
int lowestCommonAncestor = findLca(node1, node2);
return nodeDepth[node1] + nodeDepth[node2] - 2 * nodeDepth[lowestCommonAncestor];
}
// 특정 노드에서 특정 거리만큼 위로 이동
int moveUp(int node, int distance){
for (int i = 0; i < 20; i++) {
if (distance & (1 << i)) {
node = parent[node][i];
}
}
return node;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int totalNodes; cin >> totalNodes;
for (int i = 0; i < totalNodes - 1; i++) {
int node1, node2; cin >> node1 >> node2;
adjacencyList[node1].push_back(node2);
adjacencyList[node2].push_back(node1);
}
generateLcaTable(1, 0, 1);
int queries; cin >> queries;
while (queries--) {
int nodeA, nodeB, nodeC; cin >> nodeA >> nodeB >> nodeC;
int distance;
// (nodeA, nodeB) 간의 외심 후보
distance = calculateDistance(nodeA, nodeB);
if (distance % 2 == 0){
int midpoint = moveUp(nodeDepth[nodeA] > nodeDepth[nodeB] ? nodeA : nodeB, distance / 2);
if (calculateDistance(midpoint, nodeC) == distance / 2){
cout << midpoint << '\n';
continue;
}
}
// (nodeA, nodeC) 간의 외심 후보
distance = calculateDistance(nodeA, nodeC);
if (distance % 2 == 0){
int midpoint = moveUp(nodeDepth[nodeA] > nodeDepth[nodeC] ? nodeA : nodeC, distance / 2);
if (calculateDistance(midpoint, nodeB) == distance / 2){
cout << midpoint << '\n';
continue;
}
}
// (nodeB, nodeC) 간의 외심 후보
distance = calculateDistance(nodeB, nodeC);
if (distance % 2 == 0){
int midpoint = moveUp(nodeDepth[nodeB] > nodeDepth[nodeC] ? nodeB : nodeC, distance / 2);
if (calculateDistance(midpoint, nodeA) == distance / 2){
cout << midpoint << '\n';
continue;
}
}
cout << -1 << '\n';
}
return 0;
}
이 문제는 트리, LCA, 거리 계산과 같은 알고리즘적 개념을 활용하여 풀 수 있는 문제였다. LCA의 활용과 트리 구조 탐색이 중요한 핵심이었다. 최적화된 거리 계산과 조건 검증을 통해 쿼리를 효율적으로 처리할 수 있었다.