HDU 2196

简述题意:给一个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;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值