1. 程式人生 > >HDU 2196

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;
}