---
# System prepended metadata

title: 834. Sum of Distances in Tree
tags: [C++, LeetCode]

---

# LeetCode 834. Sum of Distances in Tree

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

## 題目大意

給 `n` 個樹節點還有表示他們相連情況的 `edge` (沒說是二元樹，就樹而已)
回傳 `ans` 滿足 `ans[i]` 為所有節點到第 `i` 個節點的距離和

## 思考

這題一開始肯定會想要暴力掃一圈去累算答案，但這題 `n` 有點大，用這樣 $O(n^2)$ 肯定不行

我們可以先觀察 example 1

<img src="https://assets.leetcode.com/uploads/2021/07/23/lc-sumdist1.jpg"  style="display:block;margin:auto;width:50%;height:auto;" alt="example1"><br>

這題的關鍵就是你要能想像，**我們隨便抓一個點起來，把其他點讓他垂下，就會有樹狀**

然後我們直覺就是會先隨便抓 `0` 當 `root` (因為題目沒有說誰是 `root` ，我們可以不失一般性的抓 `0` 當 `root`)，然後用 DFS 之類的去看其他節點到 `0` 的距離，假設這階段我們取得的答案叫 $\mathrm{dist}(0)$

接下來就是關鍵了，我們現在有 $\mathrm{dist}(0)$ ，以上圖而言，我們接著抓 `2` 當 `root` 時，有沒有辦法用 $\mathrm{dist}(0)$ 的結果去推導  $\mathrm{dist}(2)$ 呢？

我們可以拆兩部分來看：

首先是 `0` 跟 `1` ，他們原本 (以 `0` 當 `root`) 並不是 `2` 的子節點，但現在他們是了，這樣節點每個都相當於比原先距離再多 $1$ (可以想成這些每個都降級，深度增加，因為 `root` 換人當了)

再來是 `2` 的那顆子樹 (`2` - `5`)，他們現在反而是升級了，深度降低，所以每個都少 $1$

如果說 `2` 的子樹有 $m$ 個節點，那麼剩下的屬於我們討論的前者，有 $n-m$ 個節點

於是我們得到：

$$
\mathrm{dist}(2) = \mathrm{dist}(0) + n - 2m
$$

問題現在就簡單了，我們先用 DFS 抓 `0` 為 `root` 掃一輪得到 $\mathrm{dist}(0)$ 跟其他節點的子樹節點數
之後再抓其他節點當 `root` 套用上面的關係式，便求出所求了

```C++
class Solution
{
public:
    using Tree = vector<unordered_set<int>>;

public:
    vector<int> sumOfDistancesInTree(int n, vector<vector<int>> &edges)
    {
        this->n = n;
        vector<int> ans(n);
        vector<int> subtreeSize(n, 1);
        Tree tree(n);

        for (const auto &edge : edges)
        {
            const int u = edge[0];
            const int v = edge[1];
            tree[u].insert(v);
            tree[v].insert(u);
        }

        init(tree, 0, -1, subtreeSize, ans);
        reRoot(tree, 0, -1, subtreeSize, ans);
        return ans;
    }

private:
    int n;

    void init(const Tree &tree, int node, int parent, vector<int> &subtreeSize, vector<int> &ans)
    {
        for (const int child : tree[node])
        {
            if (child != parent)
            {
                init(tree, child, node, subtreeSize, ans);
                subtreeSize[node] += subtreeSize[child];
                ans[node] += ans[child] + subtreeSize[child];
            }
        }
    }

    void reRoot(const Tree &tree, int node, int parent, vector<int> &subtreeSize, vector<int> &ans)
    {
        for (const int child : tree[node])
        {
            if (child != parent)
            {
                ans[child] = ans[node] + n - 2 * subtreeSize[child];
                reRoot(tree, child, node, subtreeSize, ans);
            }
        }
    }
};
```
