
一个比较经典的题型,两次DFS求树上每个点的最远端距离。
参考这里:http://hi.baidu.com/oi_pkqs90/item/914e951c41e7d0ccbf904252
dp[i][0]表示最远端在以 i 为根的子树中的最长长度,dp[i][1]记录最远端在以i为根的子树中的次长长度,dp[i][2]表示最远端不在以 i 为根的子树中的最长长度。
答案即为max( dp[i][0], dp[i][2] );
dp[i][0]和dp[i][1]可以通过一次DFS得到。
再看dp[i][2], 设fa[i]为节点 i 的父节点: dp[i][2] = max( dp[ fa[i] ][2], dp[ fa[i] ][0] ) + dis[ fa[i] ][i];
显然,如果dp[ fa[i] ][0] 中的最长长度是由dp[i][0]状态转移得到的,上面的结论就不对了。
于是我们还需要记录dp[i][1]: 最远端在以i为根的子树中的次长长度。
假设best[i]表示:状态dp[i][0]是由状态dp[ best[i] ][0]转移得到,则:
if ( best[i] == fa[i] ) dp[i][2] = max( dp[ fa[i] ][2], dp[ fa[i] ][1] ) + dis[ fa[i] ][i];
else dp[i][2] = max( dp[ fa[i] ][2], dp[ fa[i] ][0] ) + dis[ fa[i] ][i];
因此还需要一次DFS求得dp[i][2], 答案即为max( dp[i][0], dp[i][2] );
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; const int MAXN = ; struct node
{
int v;
int w;
int next;
}; int N, EdgeN;
int head[MAXN];
int best[MAXN];
int dp[MAXN][];
node D[ MAXN << ]; void AddEdge( int u, int v, int w )
{
D[EdgeN].v = v;
D[EdgeN].w = w;
D[EdgeN].next = head[u];
head[u] = EdgeN++;
return;
} void DFS1( int u )
{
for ( int i = head[u]; i != -; i = D[i].next )
{
int v = D[i].v;
int w = D[i].w;
DFS1(v);
if ( dp[v][] + w > dp[u][] )
{
dp[u][] = dp[u][];
dp[u][] = dp[v][] + w;
best[u] = v;
}
else if ( dp[v][] + w > dp[u][] )
dp[u][] = dp[v][] + w;
}
return;
} void DFS2( int u )
{
for ( int i = head[u]; i != -; i = D[i].next )
{
int fa = D[i].v;
int w = D[i].w;
dp[fa][] = dp[u][] + w;
if ( fa == best[u] )
dp[fa][] = max( dp[fa][], dp[u][] + w );
else dp[fa][] = max( dp[fa][], dp[u][] + w );
DFS2( fa );
}
return;
} int main()
{
while ( scanf( "%d", &N ) == )
{
EdgeN = ;
memset( head, -, sizeof(head) );
for ( int v = ; v <= N; ++v )
{
int u, w;
scanf( "%d%d", &u, &w );
AddEdge( u, v, w );
AddEdge( v, u, w );
} memset( dp, , sizeof(dp) );
DFS1();
DFS2(); for ( int i = ; i <= N; ++i )
printf( "%d\n", max( dp[i][], dp[i][] ) );
}
return ;
}