1. 程式人生 > >hdoj 2196 Computer 樹形dp經典題

hdoj 2196 Computer 樹形dp經典題

首先簡單的樹形dp求祖宗到兒子的最長距離並記錄最短距離是哪個兒子
此時對於每個點只維護了兒子到它的最短距離
還要記錄祖宗到它的最短距離這時需要再跑一遍dfs把每個點與祖宗相關的到它的最長邊搞出來
經典模型必須熟悉啊!!!!!!

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#define maxn 10005
#define LL long long
using namespace std;
LL dp[maxn][2
], va[maxn * 2]; int Next[maxn * 2], last[maxn * 2], edge[maxn * 2], l; int n; void add(int a, int b, LL Va) { edge[l] = b; va[l] = Va; Next[l] = last[a]; last[a] = l; l++; } void dfs(int pre) { dp[pre][0] = dp[pre][1] = 0; for(int i = last[pre]; i!=-1 ; i = Next[i]) { dfs(edge[i]); if
(dp[edge[i]][0] + va[i]> dp[pre][0]) { dp[pre][0] = dp[edge[i]][0] + va[i]; dp[pre][1] = edge[i]; } } } void dfs2(int pre, LL dis, int fa) { if(dis >= dp[pre][0]) { dp[pre][0] = dis; dp[pre][1] = fa; } LL Max = dis; int
sym = -1; for(int i = last[pre]; i!=-1 ; i = Next[i]) { if(edge[i] != dp[pre][1]) { Max = max(Max, va[i] + dp[edge[i]][0]); dfs2(edge[i], va[i] + dp[pre][0], pre); } else sym = i; } if(sym != -1) dfs2(dp[pre][1], Max + va[sym], pre); } int main() { while(scanf("%d", &n)!=EOF) { l = 0; memset(last, -1 ,sizeof(last)); for(int i = 2; i<= n; i++) { int a; LL va; scanf("%d %I64d", &a, &va); add(a, i, va); } dfs(1); // for(int i = 1; i<= n; i++) printf("%I64d %I64d\n",dp[i][0], dp[i][1]); dfs2(1, 0, 0); for(int i = 1; i <= n; i++) printf("%I64d\n", dp[i][0]); } return 0; }