1405 树的距离之和(51nod)
题面:给定一棵无根树,假设它有n个节点,节点编号从1到n, 求1-n这n个节点,到其他n-1个节点的距离之和。
传送门
输入:
第一行包含一个正整数n (n <= 100000),表示节点个数。
后面(n - 1)行,每行两个整数表示树的边。
输出:
每行一个整数,第i(i = 1,2,…n)行表示所有节点到第i个点的距离之和。
这题其实挺水的 但还是想了一会
蒟蒻就用了递推,感觉好像第二个dfs有点dp的味道 emmm
思路:一看就不能暴力。因为是个无根树,所以随便拿一个点来当根都行。(本人比较习惯用1)开个数组size记录每个节点和它子节点集合的大小,开个sum用来记录dfs过程中从根节点到子节点的距离,也就是距离前缀和,f用来记录每个节点到其他所有节点的距离。
第一次:dfs我们可以从根节点向下求根节点到每个子节点的前缀和,用sum记录然后我们把每个节点的sum给了f[1]就求出根节点到所有节点的距离和了。同时回溯时,求出每个节点子集的大小,用size记录。
第二次dfs:已知根节点1到其他节点的距离和,然后还已知每个节点子集的大小,就可以用这玩意求出来f[j]=f[i]+n-2*size[j];
对于遍历到的任意一个节点 i,对于与之相邻的节点 j 来说,答案贡献由 i 到 j 转移首先减小了 size[j]
同时增加了 (n−size[j])(除了size[j]以外的点)因此可以直接得到状态转移方程f[j]=f[i]+n−size[j]∗2。
如图,如果根转移到节点2,距离首先要减少size[2]*1,然后要增加(n-size[2])*1,因为根变为节点2,节点一到节点二子集的所有距离要消失,也就是红色部分(size[v]),要增加从节点2到节点一子集的距离也就是绿色部分(n-size[v])
话不多说,上代码
#include<bits/stdc++.h>
#define cn getchar
#define ll long long
using namespace std;
void in(int &x){
int f1=1;char ch=cn();x=0;
while(ch