문제
풀이
$u$에서 $v$로 가는 경로의 가중치를 $\operatorname{W}(u, v)$라 합시다.
노드 $v$와 $v$의 서브트리에 속하는 노드 $u$에 대해서 $\operatorname{up}[v] = \sum\operatorname{W}(u, v)$로 정의합시다. 또, $v$의 서브트리에 속하는 두 노드 $a, b$에 대해 $\operatorname{in}[v] = \sum\operatorname{W}(a, b)$로 정의합시다.
트리의 루트를 임의로 1로 잡으면 구하고자 하는 답은 $\operatorname{in}[1]$입니다.
$v$의 자식 $c$에 대해 $c$와 $v$를 잇는 간선의 가중치를 $w$라 합시다. 그렇다면 $\operatorname{up}[v] = \sum (\operatorname{up}[c] + 1) \times w$ 입니다.
$\operatorname{in}[v]$의 경우에는 경로가 $c$의 서브트리 내에만 포함되는 경우, $c$의 서브트리에서 $v$로 가는 경우, 한 자식 서브트리에서 다른 자식 서브트리로 가는 경우로 나눌 수 있습니다.
경로가 $c$의 서브트리 내에만 포함되는 경우는 $\sum \operatorname{in}[c]$으로 구할 수 있습니다. $c$의 서브트리에서 $v$로 가는 경우는 $\sum (\operatorname{up}[c] + 1) \times w = \operatorname{up}[v]$로 구할 수 있습니다.
한 자식 서브트리에서 다른 자식 서브트리로 가는 경우를 $\mathcal{O}(N)$에 처리하는 것이 관건입니다.
$upSum = \operatorname{up}[v]$로 초기화합시다. 각 자식 $c$에 대해 $upSum$에서 $(\operatorname{up}[c] + 1) \times w$를 뺀 뒤 $upSum$과 $(\operatorname{up}[c] + 1) \times w$를 곱하면 $c$의 서브트리에서 다른 자식 서브트리로 가는 경우를 중복 없이 셀 수 있습니다.
좀 더 자세히 설명해 보겠습니다. $(\operatorname{up}[c] + 1) \times w$를 $f(c)$로 나타내 봅시다. 우리가 구하고 싶은 것은 $v$의 자식 $a, b, c, \dots$에서 두개를 뽑아 곱한 것을 모두 더한 값 $f(a)f(b) + f(a)f(c) + \dots + f(b)f(c) + f(b)f(d) + \dots$입니다.
두개를 뽑을 때 하나가 $a$인 경우는 $f(a)(f(b) + f(c) + f(d) + \dots)$로 계산할 수 있습니다. 이는 $f(a)(\operatorname{up}[v] - f(a))$와 같음을 알 수 있습니다.
두개를 뽑을 때 하나가 $b$인 경우는 $f(b)(f(a) + f(c) + f(d) + \dots)$이지만 $a$가 뽑히는 경우는 이미 계산했으므로 이를 제외하면 $f(b)(f(c) + f(d) + \dots)$이고 이는 $f(b)(\operatorname{up}[v] - f(a) - f(b))$와 같음을 알 수 있습니다.
따라서 $upSum = \operatorname{up}[v]$로 초기화한 뒤 $upSum$에서 $f(c)$를 빼고 $upSum$과 $f(c)$를 곱한 값을 모두 더해주면 한 자식 서브트리에서 다른 자식 서브트리로 가는 경로의 가중치의 합을 구할 수 있습니다.
시간 복잡도는 $\mathcal{O}(N)$입니다.
코드
1 | |