트리 위의 분할 정복
배열의 분할 정복은 "절반으로 쪼개 각각 풀고, 경계를 가로지르는 경우만 따로
합친다." 트리에서 이를 흉내 내는 것이 센트로이드 분할(centroid
decomposition) 이다. "경로 길이가 정확히 \(K\)인 쌍의 수" 같은 모든 정점
쌍/경로 문제에 강력하다.
무게중심(센트로이드)
트리의 무게중심은 그 정점을 제거했을 때 남는 모든 조각의 크기가
\(\lfloor N/2 \rfloor\) 이하가 되는 정점이다. 모든 트리에는 무게중심이 (1개
또는 2개) 항상 존재한다.
핵심 성질: 무게중심을 기준으로 트리를 쪼개면, 각 조각의 크기가 절반 이하다.
그래서 재귀 깊이가 \(O(\log N)\)이다.
무게중심을 \(c\)라 하면, 트리의 모든 경로는 (1) \(c\)를 지나거나 (2) \(c\)를 떼어
낸 어떤 한 조각 안에 완전히 들어간다. (1)을 \(c\)에서 한 번에 처리하고, (2)는 각
조각에 대해 재귀하면 모든 경로를 빠짐없이 한 번씩 본다.
무게중심 찾기
- 한 번의 DFS로 각 정점의 서브트리 크기
sz를 구한다. - 현재 조각 크기를
total이라 할 때, 어떤 정점에서 (가장 큰 자식 조각 크기)와
(\(total - sz[\text{현재}]\), 즉 부모 쪽 조각)가 모두 \(\le total/2\)이면 그
정점이 무게중심이다.
\(O(\text{조각 크기})\)에 찾는다.
분할 정복 절차
- 현재 조각의 무게중심 \(c\)를 찾는다.
- \(c\)를 "삭제됨"으로 표시하고, \(c\)를 지나는 경로의 기여를 계산한다(보통
각 조각에서 \(c\)까지의 거리를 모아 카운팅). - \(c\)를 떼어 낸 각 인접 조각에 대해 재귀한다.
복잡도
재귀 깊이가 \(O(\log N)\)이고, 각 깊이에서 모든 정점이 정확히 한 번씩 어떤
무게중심의 조각에 속한다. 깊이마다 처리 비용이 \(O(N)\)(또는 정렬·이분 탐색이면
\(O(N \log N)\))이라 전체 \(O(N \log N)\) 또는 \(O(N \log^2 N)\)이다.
핵심 보장: 한 정점은 \(O(\log N)\)개의 무게중심 조각에만 속한다. 이 사실이
모든 센트로이드 분할 풀이의 복잡도 근거다.
무엇을 푸나
"거리가 \(\le K\)인 정점 쌍 수", "거리가 정확히 \(K\)인 쌍 수", 그리고 동적으로
정점에 색을 칠하며 "가장 가까운 특정 색 정점까지 거리"를 묻는 문제(센트로이드
트리에 보조 정보 저장)까지 다룬다.