題意:輸入 個結點,然後輸入 行,兩個數字 ,表示,(第 行) 是 的子結點。求每個結點距離他最遠的距離。( 號結點爲根結點)
思路:
結點 的子樹到 的最長距離
結點 的子樹到 的次長距離
從結點 往上走的最長距離
每個結點的最長和次長距離我們用 的方式自下而上的去更新(保證次長和最長分別分佈在左右子樹上),算出 和 後,如果要計算 的上面的最長距離,我們可以發現:
如果 不在其父親的最長鏈上,那麼距離他最長的距離就是
如果 在其父親的最長鏈上,那麼距離他最長的距離就是
上述語言符號化:
兒子在父親的最長鏈上
兒子不在父親的最長鏈上
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Max_n = 1e4 + 10;
int head[Max_n], cnt;
ll dp[Max_n][3];
struct Edge {
int u, v, w, next;
} edge[Max_n << 1];
void addedge(int u, int v, int w) {
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
void dfs1(int u) {
ll one = 0, two = 0;
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
dfs1(v);
ll cost = dp[v][0] + (ll)edge[i].w;
if(cost >= one) {
two = one;
one = cost;
}
if(cost < one && cost > two) {
two = cost;
}
}
dp[u][0] = one;
dp[u][1] = two;
}
void dfs2(int u) {
for(int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if(dp[v][0] + (ll)edge[i].w == dp[u][0])
dp[v][2] = max(dp[u][2], dp[u][1]) + (ll)edge[i].w;
else
dp[v][2] = max(dp[u][2], dp[u][0]) + (ll)edge[i].w;
dfs2(v);
}
}
int main() {
int n;
while(~scanf("%d", &n)) {
cnt = 0;
for(int i = 1; i <= n; i++)
head[i] = -1;
for(int i = 2; i <= n; i++) {
int u, w;
scanf("%d%d", &u, &w);
addedge(u, i, w); //i 是 u 的子結點
}
memset(dp, 0, sizeof(dp));
dfs1(1);
dfs2(1);
for(int i = 1; i <= n; i++)
printf("%lld\n", max(dp[i][0], dp[i][2]));
}
return 0;
}
/**
* Copyright(c)
* All rights reserved.
* Author : Max_n
* Date : 2019-10-07-21.39.43
* Problem : hdu 2196 Computer
*/