思路:先选定1为树根,进行第一次深搜,很容易求出节点u到其子节点的最长距离和次长距离,求次长距离的目的是如果u的跟节点最长路径经过u则dp的时候就不能取其跟节点的最长距离,应该取其次长距离;然后进行第二次深搜,搜索节点u经过其跟节点的最长距离。如果令dp[u][0],dp[u][1],分别为节点u到子节点的最长,次长距离,dp[u][2]表示节点u经过其跟节点v的最长距离,则状态方程为 dp[u][2] = max(dp[v][2],dp[u][0] + edge[j].w == dp[v][0] ? dp[v][1] : dp[v][0]) + edge[j].w;最后输出答案为max(dp[u][0],dp[u][2]),即某点u的最长距离为其到子节点的最长距离和经过其跟节点的最长距离二者之中的最大者。
#include #include #include #define MAX 11111using namespace std;typedef long long int LL;typedef struct{ int to, next, w;}Node;Node edge[MAX];LL head[MAX], dp[MAX][3];void AddEdge(int u, int v, int w, int i){ edge[i].to = v; edge[i].w = w; edge[i].next = head[u]; head[u] = i;}void dfs_to_son(int i){ LL bigest = 0, biger = 0; for(int j = head[i];j != -1;j = edge[j].next){ int v = edge[j].to; dfs_to_son(v); LL temp = dp[v][0] + edge[j].w; if(bigest <= temp){ biger = bigest; bigest = temp; }else if(temp > biger) biger = temp; } dp[i][0] = bigest; dp[i][1] = biger;}void dfs_to_father(int i){ for(int j = head[i];j != -1;j = edge[j].next){ int v = edge[j].to; dp[v][2] = max(dp[i][2], dp[v][0] + edge[j].w == dp[i][0] ? dp[i][1]:dp[i][0]) + edge[j].w; dfs_to_father(v); }}int main(){ int n, u, w; /* freopen("in.c", "r", stdin); */ while(~scanf("%d", &n)){ memset(dp, 0, sizeof(dp)); memset(head, -1, sizeof(head)); for(int i = 2;i <= n;i ++){ scanf("%d%d", &u, &w); AddEdge(u, i, w, i-1); } dfs_to_son(1); dfs_to_father(1); for(int i = 1;i <= n;i ++) printf("%lld\n", max(dp[i][2], dp[i][0])); } return 0;}