834. Sum of Distances in Tree
解题思路
该题目需要求解树中每个点到所有点的距离之和,可以通过树形DP来进行求解。
下面是一棵树,最上面的节点时根节点。为了通用性,我们来计算红色节点对应到所有节点的距离。
树形DP其实都是DFS进行计算的,因此我们会从根节点进行DFS。到了红色节点之后,其实要计算的距离分为两部分:第一部分是到子节点的距离,第二部分是从父节点到其余节点的距离。
对于到子节点的距离down[i],我们可以在DFS中,利用从子节点搜集到的信息直接计算。假设红色节点是i,子节点是j。则down[i] = down[j] + cnt[j]。down[i]表示所有以i为根节点的子节点到i节点的距离。cnt[i]表示以i为根节点,节点数目。
对于从父节点到其余节点的距离up[i],假设父节点为u,该距离等于父亲到其余节点的距离+节点个数。根据图示,up[i] = up[u](父节点朝上的距离) +down[u](父节点朝下的距离) - (down[j] + cnt[j])(父节到j的距离) + (总结点数 - cnt[j])(父节点涉及到的节点数目)。
代码
const int N = 20010;
int h[N], e[N], ne[N];
int idx;
int down[N], up[N], cnt[N];
int n;
void add(int a, int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
class Solution {
public:
void dfs_down(int u, int father) {
down[u] = 0;
cnt[u] = 1;
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == father) {
continue;
}
dfs_down(j, u);
down[u] += down[j] + cnt[j];
cnt[u] += cnt[j];
}
}
void dfs_up(int u, int father) {
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == father) {
continue;
}
up[j] = up[u] + down[u] - down[j] - cnt[j] + n - cnt[j];
dfs_up(j, u);
}
}
vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) {
n = N;
memset(h, -1, sizeof h);
idx = 0;
for (auto e: edges) {
int a = e[0], b = e[1];
add(a, b);
add(b, a);
}
dfs_down(0, -1);
dfs_up(0, -1);
vector<int> ans;
for (int i = 0; i < N; i ++) {
ans.push_back(down[i] + up[i]);
}
return ans;
}
};