题目:HDU-2196
题意:给定一棵树,每条树边附带边权,求每个点的在这棵树上能够去到的最远距离
思路:
树形dp,做两次dfs
第一次dfs得到每个节点到它子树中节点的最远距离和次远距离,然后第二次dfs得到经过父亲到当前节点的最远距离
第二次dfs时是用父亲的最远距离 + 边权(父亲,儿子)来更新状态,因此需要用son记录父亲的最远距离和次远是经过了哪个儿子得到的,防止当前节点被计算两次
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 10;
struct node
{
int to, val, next;
node(){}
node(int t, int v, int n) :to(t), val(v), next(n){}
}edge[N << 1];
int head[N], cnt;
int n, w, u, v;
int dp[N][3], son[N][2];
//dp[][j], j = 0, 1, 2的时候分别代表在子树中能够去到的最远距离,次远距离,和经过父亲的最远距离
//son则是记录最远和次远距离是经过了哪个儿子
void init()
{
memset(dp, 0, sizeof dp);
memset(head, -1, sizeof head);
cnt = 0;
}
void add(int u, int v, int w)
{
edge[cnt] = node(v, w, head[u]);
head[u] = cnt ++;
}
void dfs1(int u)
{
for(int i = head[u]; i + 1; i = edge[i].next)
{
int v = edge[i].to, w = edge[i].val;
dfs1(v);
int res = dp[v][0] + w, t = v;
if(res > dp[u][0])
{
swap(res, dp[u][0]);
swap(t, son[u][0]);
}
if(res > dp[u][1])
{
swap(res, dp[u][1]);
swap(t, son[u][1]);
}
}
}
void dfs2(int u)
{
for(int i = head[u]; i + 1; i = edge[i].next)
{
int v = edge[i].to, w = edge[i].val;
if(son[u][0] == v)
dp[v][2] = max(dp[u][1], dp[u][2]) + w;
else
dp[v][2] = max(dp[u][0], dp[u][2]) + w;
dfs2(v);
}
}
int main()
{
// freopen("1.txt", "r", stdin);
while(~scanf("%d", &n))
{
init();
for(v = 2; v <= n; v ++)
{
scanf("%d%d", &u, &w);
add(u, v, w);
}
dfs1(1);
dfs2(1);
for(int i = 1; i <= n; i ++)
printf("%lld\n", max(dp[i][0], dp[i][2]));
}
return 0;
}