HDU
来源:互联网 发布:自己的域名 编辑:程序博客网 时间:2024/06/04 17:47
传送门
//就是输出每个点的最远距离.
其实我来写首先会有树的直径, 那么就变得很简单了, 但是都说树形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])); } }}
阅读全文
0 0