给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和。
输入
第一行包含一个正整数n (n <= 100000),表示节点个数。
后面(n - 1)行,每行两个整数表示树的边。
输出
每行一个整数,第i(i = 1,2,…n)行表示所有节点到第i个点的距离之和。
输入样例
4
1 2
3 2
4 2
输出样例
5
3
5
5

先选定节点1作为树的根,然后用num[i]表示以节点i为根的子树上的节点数(包括i)。

dp[x]表示节点x到其他所有节点距离之和,设节点x是节点xx的父节点。

那么我们可以得到dp[xx] = dp[x] + (n-num[xx]) - num[xx]。

因为在xx子树上的节点到xx的距离要比到父节点x的距离要少1,所以减去1,一共有num[xx]个,所以减去num[xx]

不在xx子树上的节点到xx的距离要比到父节点x的距离要多1,所以加上n - num[xx]。

这样我们首先一个dfs处理出dp[1]的大小,就可以推出其他的大小。


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
int n;
ll dp[maxn];
int vis[maxn], num[maxn];
vector<int> e[maxn];

void dfs(int x, int s) {
	vis[x] = 1; 
	num[x] = 1;
	dp[1] += s;
	for (int i = 0; i < e[x].size(); i++) {
		int xx = e[x][i];
		if (vis[xx] == 0) {
			dfs(xx, s + 1);
			num[x] += num[xx];
		}
	}
}

void init_dp(int x) {
	vis[x] = 1;
	for (int i = 0; i < e[x].size(); i++) {
		int xx = e[x][i];
		if (vis[xx] == 0) {
			dp[xx] = dp[x] + (n - num[xx]) - num[xx];
			init_dp(xx);
		}
	}
}


int main() {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n;
	int u, v;
	for (int i = 1; i <= n - 1; i++) {
		cin >> u >> v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	dp[1] = 0;
	memset(vis, 0, sizeof(vis));
	dfs(1, 0);
	memset(vis, 0, sizeof(vis));
	init_dp(1);
	for (int i = 1; i <= n; i++) {
		cout << dp[i] << endl;
	}
	return 0;
}