HDU2196
题解
- 在一棵树上,求每个结点能到达的最远距离。
- 设结点到子树的最大距离为深度。那么结点能到达的最远距离可能为深度(1),也可能为经过先到父结点再到兄弟结点的子树(2),或者直接一直往上走到另一边(3)。
- 如果u的父节点到子树的最大距离经过u,那么u的最远距离为max(1,2,3)。
- 如果u的父节点到子树的最大距离不经过u,那么max(2,3)。
- 先自底向上dfs一遍。记录最大距离和相应的子节点,记录次大距离(2好方案所需)。
- 在自顶向下dfs一遍。dp[0][i]表示最大距离,dp[1][i]表示次大距离,dp[2][i]表示2和3号方案的最大的距离。
- 注意dp过程中先记录2和3的最大值,最后再和1取最大。否则出错,因为包含了到子树的最大距离了。
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 10000 + 10;
struct Node
{
int to,val;
Node(){};
Node(int to,int val):to(to),val(val){}
};
vector<Node>G[N];
int n,dp[3][N],id[N];
void dfs1(int u,int fa){
for(int i=0;i<G[u].size();i++){ //找最长
Node v = G[u][i];
if(v.to == fa) continue;
dfs1(v.to,u);
if(dp[0][u] < dp[0][v.to] + v.val){
dp[0][u] = dp[0][v.to] + v.val;
id[u] = v.to;
}
}
for(int i=0;i<G[u].size();i++){ //次短路
Node v = G[u][i];
if(v.to == fa) continue;
if(v.to == id[u]) continue; //在另外一个子节点上找
dp[1][u] = max(dp[1][u],dp[0][v.to] + v.val);
}
}
void dfs2(int u,int fa){
for(int i=0;i<G[u].size();i++){
Node v = G[u][i];
if(v.to == fa) continue;
if(v.to == id[u]){ //u的最长路经过子节点
dp[2][v.to] = max(dp[2][u],dp[1][u]) + v.val;
}else{
dp[2][v.to] = max(dp[2][u],dp[0][u]) + v.val;
}
dfs2(v.to,u);
}
}
int main(){
while(~scanf("%d",&n)){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++) G[i].clear();
for(int i=2;i<=n;i++){
int u,len;
scanf("%d%d",&u,&len);
G[i].push_back(Node(u,len));
G[u].push_back(Node(i,len));
}
dfs1(1,-1);
dfs2(1,-1);
for(int i=1;i<=n;i++) printf("%d\n",max(dp[0][i],dp[2][i]));
}
return 0;
}