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])(父节点涉及到的节点数目)。
image.png

代码

  1. const int N = 20010;
  2. int h[N], e[N], ne[N];
  3. int idx;
  4. int down[N], up[N], cnt[N];
  5. int n;
  6. void add(int a, int b) {
  7. e[idx] = b;
  8. ne[idx] = h[a];
  9. h[a] = idx ++;
  10. }
  11. class Solution {
  12. public:
  13. void dfs_down(int u, int father) {
  14. down[u] = 0;
  15. cnt[u] = 1;
  16. for (int i = h[u]; i != -1; i = ne[i]) {
  17. int j = e[i];
  18. if (j == father) {
  19. continue;
  20. }
  21. dfs_down(j, u);
  22. down[u] += down[j] + cnt[j];
  23. cnt[u] += cnt[j];
  24. }
  25. }
  26. void dfs_up(int u, int father) {
  27. for (int i = h[u]; i != -1; i = ne[i]) {
  28. int j = e[i];
  29. if (j == father) {
  30. continue;
  31. }
  32. up[j] = up[u] + down[u] - down[j] - cnt[j] + n - cnt[j];
  33. dfs_up(j, u);
  34. }
  35. }
  36. vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) {
  37. n = N;
  38. memset(h, -1, sizeof h);
  39. idx = 0;
  40. for (auto e: edges) {
  41. int a = e[0], b = e[1];
  42. add(a, b);
  43. add(b, a);
  44. }
  45. dfs_down(0, -1);
  46. dfs_up(0, -1);
  47. vector<int> ans;
  48. for (int i = 0; i < N; i ++) {
  49. ans.push_back(down[i] + up[i]);
  50. }
  51. return ans;
  52. }
  53. };