题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1405
题意:
给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和。
Input
第一行包含一个正整数n (n <= 100000),表示节点个数。
后面(n - 1)行,每行两个整数表示树的边。
Output
每行一个整数,第i(i = 1,2,…n)行表示所有节点到第i个点的距离之和。
Input示例
4
1 2
3 2
4 2
Output示例
5
3
5
5
分析:
分析父节点和一个子节点,如果知道了父节点的和,那么子节点的和是多少呢?
dp[v]=dp[u]-siz[v]+(n-siz[v]);
因为子节点所在子树的所有点到父节点的那条边都少了1,总共减去siz[v]
通过父节点到子节点的所有节点都经过了这条边,都加1,总共加上n-siz[v]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000+7;
int siz[maxn];
ll dp[maxn];
int n;
vector<int>e[maxn];
void dfs(int u,int fa) {
siz[u]++;
for(int i = 0; i<e[u].size(); i++) {
int v = e[u][i];
if(v==fa)continue;
dfs(v,u);
siz[u]+=siz[v];
dp[1]+=siz[v];
}
}
void dfs1(int u,int fa) {
for(int i = 0; i<e[u].size(); i++) {
int v = e[u][i];
if(v==fa)continue;
dp[v]=dp[u]-siz[v]+(n-siz[v]);
dfs1(v,u);
}
}
int main() {
scanf("%d",&n);
for(int i = 1; i<=n-1; i++) {
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,-1);
dfs1(1,-1);
for(int i = 1; i<=n; i++)
printf("%lld\n",dp[i]);
return 0;
}