传送门
//就是输出每个点的最远距离.
其实我来写首先会有树的直径, 那么就变得很简单了, 但是都说树形dp必做, 那么就用树形dp来好一点.
dp[maxn][3];
dp[u][0] 代表u的子树下距离u最远的距离是多少.
dp[u][1]代表u的子树下距离u 次 远的距离是多少.
dp[u][2] 代表经过u的父亲最远可以到达的距离.
所以转移方程方程就是:
dp[u][0] = dp[v][0] + w[i]; 所以这个需要从下往上做.
dp[v][2] = max(dp[u][2],dp[v][0] +w[i] == dp[u][0]? dp[u][1] : dp[u][0])+w[i]; 这个需要从上往下做.
// 里面那个 代表 如果 父亲可以到达的最远距离就是走的当前儿子所在的这颗子树, 那么就选父亲可以到达的次远距离, 否则就选最远距离赛.
所以两次dfs后, ans = max(dp[i][0],dp[i][2]);
AC Code
const int maxn = 1e4+5;
int cas=1;
int cnt,head[maxn];
struct node
{
int to,w,next;
}e[maxn*2];
void add(int u,int v,int w)
{
e[cnt] = (node){v,w,head[u]};
head[u] = cnt++;
}
int dp[maxn][3];
void dfs_dowm_up(int u,int fa)
{
for(int i=head[u] ; ~i ; i = e[i].next){
int to = e[i].to;
if(fa == to) continue;
dfs_dowm_up(to,u);
int w = dp[to][0] + e[i].w;
if(w>dp[u][0]){
dp[u][1] = dp[u][0];
dp[u][0] = w;
}
else if(w > dp[u][1]){
dp[u][1] = w;
}
}
}
void dfs_up_down(int u,int fa)
{
for(int i=head[u] ; ~i ; i = e[i].next){
int to = e[i].to;
if(fa == to) continue;
dp[to][2] = max(dp[u][2],dp[to][0]+e[i].w == dp[u][0]?dp[u][1]:dp[u][0]) + e[i].w;
dfs_up_down(to,u);
}
}
void solve()
{
int n;
while(~scanf("%d",&n)){
cnt = 0 ; Fill(head,-1);
Fill(dp,0);
for(int i=2;i<=n;i++){
int v,w;
scanf("%d%d",&v,&w);
add(i,v,w); add(v,i,w);
}
dfs_dowm_up(1,-1);
dfs_up_down(1,-1);
for(int i=1;i<=n;i++){
printf("%d\n",max(dp[i][0],dp[i][2]));
}
}
}