---
# System prepended metadata

title: LeetCode 834 (換根DP)
tags: [題解, ' 動態規劃', ' 樹']

---

---
title: "LeetCode 834 (換根DP)"
tags: 題解, 樹, 動態規劃
---

https://leetcode.com/problems/sum-of-distances-in-tree/

#### 題意

給一棵無根樹，求出以每個節點作為根時，所有點與根的距離之和。

#### 思路

換根DP，先 DFS 求出以 $u$ 為根時，子樹的節點數以及節點到 $u$ 的距離之和。

第二次 DFS 考慮 $u$ 為根而 $v$ 為其子節點時，已知 $dist[u]$ 為所有點到 $u$ 的距離之和，而 $dist[v]$ 為以 $v$ 為根的子樹中所有點到 $v$ 的距離之和。也就是說，對於 $v$ 而言，還差以 $u$ 為根的子樹的貢獻，將 $dist[u]$ 排除 $v$ 子樹的貢獻後，加上 $u$ 子樹的節點數，即為從 $u$ 轉移至 $v$ 的貢獻。

#### Code

```python=1
class Solution:
    def sumOfDistancesInTree(self, n: int, edges: List[List[int]]) -> List[int]:
        def dfs(node, prev):
            # get sum of dist and num of nodes from
            # subtree rooted at `node`
            for neigh in adj[node]:
                if neigh == prev:
                    continue
                dfs(neigh, node)
                dists[node] += dists[neigh] + nodes[neigh]
                nodes[node] += nodes[neigh]

        def dfs2(node, prev):
            # rerooting dp
            for neigh in adj[node]:
                if neigh == prev:
                    continue
                dists[neigh] += (dists[node] - (dists[neigh] + nodes[neigh])) + (n - nodes[neigh])
                dfs2(neigh, node)

        adj = defaultdict(list)
        for (a, b) in edges:
            adj[a].append(b)
            adj[b].append(a)

        dists = [0 for _ in range(n)]
        nodes = [1 for _ in range(n)]
        dfs(0, -1)
        dfs2(0, -1)
        return dists
```