# 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);
}
}
}
};
```