版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/84989553
简述题意:给一个n个点的带边权树,求每个点能到的最远距离。
一般题意:
有连续n台电脑加入,每台电脑会和之前已经加入的电脑相连,并且边有一个权值,求每个电脑的最远的距离。
对于每个点 其到最远距离只有两个来源:
1 来自他的子树, 2来自父节点
对于第一种情况自然很好处理,但是第二种情况,我们就需要考虑了,开始的时候太蠢了,只想到根到当前节点就是最远,但是没想到可以是从另外一边追溯到根节点再到当前节点,那么我们就得考虑一下如何解决了。
对于一个父节点,我们可能在左子节点或有右侧节点或者更多子节点上 找到一个更加好的,思考一下,这不就是找一个次长节点,把她和最长节点连接起来,对于最长那个节点不就是一条最长的从父节点那里获得的距离。
所以可能需要3个dp 了,一个存向下遍历最大,一个存向下次大,最后一个存向上最大。
向上最大我们可以从父节点向下遍历的时候得出来,所以先跑一边向下,最后跑一边向上,得出结果。
当然对于向上遍历的过程,我们先判断当前节点是不是对于父节点来讲的最大距离点,如果是,就把他和他父节点的次大连起来,否则就把他和最大连起来,求得从父节点那边获得最大距离。
很精彩的一道题。。。。
以下为 AC 代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+5;
struct node
{
int to,nxt,w;
}ed[maxn];
int head[maxn],tot;
int dp[maxn][3];
int len[maxn];
void add(int x,int y,int w)
{
ed[++tot].to = y;
ed[tot].nxt = head[x];
ed[tot].w = w;
head[x] = tot;
}
void dfs_down(int u)
{
int mxx = -1, mx = -1;
for(int i=head[u];~i;i=ed[i].nxt)
{
int v = ed[i].to;
dfs_down(v);
int tmp = dp[v][0]+ed[i].w;
if(mxx <= tmp)
{
mx = mxx;
mxx = tmp;
}
else if(mx < tmp)
mx = tmp;
}
dp[u][0] = mxx;
dp[u][1] = mx;
}
void dfs_up(int u)
{
for(int i=head[u];~i;i=ed[i].nxt)
{
int v = ed[i].to;
dp[v][2] = max(dp[u][2] , dp[v][0] + ed[i].w == dp[u][0] ? dp[u][1] : dp[u][0]) + ed[i].w;
dfs_up(v);
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(head,-1,sizeof head);
tot = 1;
for(int v=2;v<=n;v++)
{
int u,w;
scanf("%d%d",&u,&w);
add(u,v,w);
}
dfs_down(1);
dp[1][2] = 0;
dfs_up(1);
for(int i=1;i<=n;i++)
printf("%d\n",max(dp[i][0],dp[i][2]));
}
return 0;
}