무엇을 해결하나
트리에서 "정점 \(u\)와 \(v\) 사이 경로상의 합/최댓값을 구하라", "경로상 모든 정점에
\(x\)를 더하라" 같은 경로 질의·갱신을 빠르게 처리하는 기법이 헤비-라이트
분할(HLD) 이다. 단순히 LCA까지 한 칸씩 올라가면 한 질의에 \(O(N)\)이 들 수
있는데, HLD는 이를 \(O(\log^2 N)\)으로 줄인다.
헤비 간선과 라이트 간선
각 정점에서 서브트리 크기가 가장 큰 자식으로 가는 간선을 헤비 간선,
나머지를 라이트 간선이라 한다.
핵심 보조정리: 루트에서 임의의 정점까지 내려가는 동안 라이트 간선은 최대
\(O(\log N)\)번 거친다.
이유는 라이트 간선을 한 번 탈 때마다 서브트리 크기가 절반 미만으로 줄기
때문이다(헤비가 아니므로 그 자식 서브트리는 부모 서브트리의 절반 이하). 절반씩
줄어드니 \(\log N\)번이면 끝난다.
사슬(chain)로 묶기
헤비 간선으로 이어진 정점들을 하나의 사슬로 묶는다. 그러면 트리 전체가
\(O(\log N)\) 깊이의 사슬 구조로 분해된다. 각 사슬 안의 정점들에게 연속된
번호(DFS 순서) 를 부여하면, 한 사슬 위의 구간이 배열의 연속 구간이 된다.
여기에 세그먼트 트리(필요하면 lazy)를 얹으면 사슬 내 구간 질의/갱신이
\(O(\log N)\)이다.
경로 질의 처리
\(u \to v\) 경로를 처리할 때, 두 정점 중 사슬 머리(head)가 더 깊은 쪽을 그 사슬
머리까지 한 번에 점프시키며 그 구간을 세그 트리로 질의한다. 같은 사슬에 올
때까지 반복하면, 경로가 \(O(\log N)\)개의 사슬 구간으로 쪼개진다. 각 구간
질의가 \(O(\log N)\)이므로 한 경로 질의가 \(O(\log^2 N)\)이다.
$$ \underbrace{O(\log N)}_{\text{사슬 점프 횟수}} \times \underbrace{O(\log N)}_{\text{세그 트리 질의}} = O(\log^2 N) $$
정점 vs 간선 가중치
가중치가 간선에 있으면, 각 간선을 그 자식 정점에 귀속시키고 경로 질의
시 LCA 정점은 제외한다. 이 한 가지 처리만 정확히 하면 정점 버전과 거의 같다.