思路
基础树形dp,但看了题解才做出来。。
树形dp有两种基本形式:从根到叶子,从叶子到根。本题稍微有点特别,需要进行两次dfs才能完成整个dp。
我们定义一个dp数组dp[MAXN][3]。dp[i][0]记录的是节点i子树中所有节点到子树根节点i的最大距离,dp[i][1]记录的是节点i往根方向的最大距离,dp[i][2]记录的是节点i子树中所有点的到子树根节点i的次大距离。为什么要这样设计dp状态?如果我们将i节点设为根节点,我们能发现原来父亲节点也变成了一棵子树。但我们不能对每个节点都dfs一次,所以我们考虑使用一个dp[i][1]从顶向下来计算父亲节点这棵子树的距离最大值,dp[i][0],dp[i][2]的作用在后文中会写到。
对于dp[i][0],dp[i][2]我们在第一次dfs中就计算出来,注意我们要记录一个一个点最长距离走的是哪个儿子longest[i],这个值在后面会用到。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17int dfs1(int u,int fa){
dp[u][0]=0;
for(int i=head[u];~i;i=nxt[i]){
int go=to[i];
if(go==fa)continue;
int temp=dfs1(go,u)+len[i];
if(temp>dp[u][0]){
dp[u][2]=dp[u][0];
dp[u][0]=temp;
islongest[u]=go;
}
else if(temp>dp[u][1]){
dp[u][1]=temp;
}
}
return dp[u][0];
}
在第二次dfs中我们计算dp[i][1]。我们在父亲节点时计算儿子节点的dp[son][1]而不是dfs进入儿子后计算。然后分类讨论
- 对于不是longest的儿子节点,我们显然知道往根方向的最大值是儿子节点到当前节点的距离+当前节点中儿子的最大值和dp[i][1]中的较大值
- 是longest的儿子节点,往根方向的最大值是儿子节点到当前节点的距离+dp[i][2]和dp[i][1]中的较大值(注意此时原来所有儿子中的最大值已经不能使用了,因为这个最大值包含在dp[son][0]中,此时只能选择次大值)
最后遍历所有节点取max(dp[i][0],dp[i][1])即可
代码
1 |
|