HDU2196.Computer(樹形DP)
思路:每個結點的最大距離轉化爲到子樹結點的最大距離與到上部最大的距離的較大值。到上部最大距離要分兩種情況(在最長距離子樹上和不在最長距離子樹上)通過兩次DFS就可完成狀態轉移。具體看代碼。
AC代碼:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node{
int id,d;
};
vector<node>e[N];
int dp[N][3],n; //dp[i][0],dp[i][1],dp[i][2] 分別表示結點i到子樹最大距離,次大距離,和結點i到上部的最大距離
void dfs1(int u){ //dfs1 求結點u到子樹的最大距離和第二大距離(以便於分情況討論)
int d1=0,d2=0;
for(auto v:e[u]){
dfs1(v.id);
int tmp=dp[v.id][0]+v.d;
if(tmp>=d1){ //更新最大距離和次大距離
d2=d1,d1=tmp;
}
else if(tmp<d1&&tmp>d2) d2=tmp;//更新次大距離
}
dp[u][0]=d1,dp[u][1]=d2;
}
void dfs2(int u){
for(auto v:e[u]){
if(dp[v.id][0]+v.d==dp[u][0]) //若子結點在u的最長子樹上.則要用次大距離來更新
dp[v.id][2]=max(dp[u][2],dp[u][1])+v.d;
else dp[v.id][2]=max(dp[u][2],dp[u][0])+v.d;//否則用最長子樹更新.
dfs2(v.id);
}
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++) e[i].clear();
memset(dp,0,sizeof dp);
for(int i=2,x,y;i<=n;i++){
scanf("%d%d",&x,&y);
e[x].push_back({i,y});
}
dfs1(1);
dfs2(1);
for(int i=1;i<=n;i++)
printf("%d\n",max(dp[i][0],dp[i][2]));
}
return 0;
}