51nod 1405 樹的距離之和 搜尋+DP
第一行包含一個正整數n (n <= 100000),表示節點個數。 後面(n - 1)行,每行兩個整數表示樹的邊。Output
每行一個整數,第i(i = 1,2,...n)行表示所有節點到第i個點的距離之和。Input示例
4 1 2 3 2 4 2Output示例
5 3 5
5
假設以第一個點為根節點,我們開始搜尋,記錄以當前節點的深度以及當前節點的子節點個數。
之後對於統計。
對於X節點,我們已經知道他的距離之和為dp【X】了。
那麼他的子節點Y節點。
dp【Y】=dp[X] - num[y] + n - num[y]
解釋一下:其他點到達y,有兩種情況。第一種點在y節點的子樹上。 也就是num【y】個,這num【y】個點
到達y要比到達x小1. 所以dp【x】-num【y】. 第二種情況,不在y的子樹上的點,也就是n-num【y】個,
他們要比到達x多1.所以在原來的基礎上再加上n - num[y]。
那麼我們dfs來求dp即可。
#include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<iostream> using namespace std; vector<long long>p[100010]; bool f[100010];//是否訪問過 long long dp[100010];//當前深度到S的深度 long long num[100010];//子節點數量 long long n; void dfs(long long s,long long depth) { long long len=p[s].size(); f[s]=1; num[s]=1; dp[1]+=depth; for(long long i=0;i<len;i++) { if(!f[p[s][i]]) { dfs(p[s][i],depth+1); num[s]+=num[p[s][i]]; } } } void solve(long long s) { long long len=p[s].size(); f[s]=1; for(long long i=0;i<len;i++) { if(!f[p[s][i]]) { dp[p[s][i]]=dp[s]+n-num[p[s][i]]*2; solve(p[s][i]); } } } int main() { cin>>n; for(long long i=2;i<=n;i++) { long long a,b; cin>>a>>b; p[a].push_back(b); p[b].push_back(a); } dfs(1,0); memset(f,0,sizeof(f)); solve(1); for(long long i=1;i<=n;i++) cout<<dp[i]<<endl; }