HDU 2196

来源:互联网 发布:sql 别名的使用 编辑:程序博客网 时间:2024/05/27 06:52


//树形DP,求树的最大直径。。。。

#include<stdio.h>

#include<string.h>
#include<vector>
using namespace std;
#define Max(x,y) (x>y?x:y)
#define max 10000+5

vector<int> next[max];//存图
int n,cost[max],dp[max],sec[max],up[max],f[max];
//dp[i] 结点i在其子树上的最大直径
//sec[i]结点i在其子树上的次最大直径
//up[i] 结点i通过其父结点可获得的最大直径
//f[i]  结点i在其子树上获得最大直径所通过的子结点


void init(){
    for(int i=0;i<=n;i++){
        next[i].clear();
    }
    memset(sec,0,sizeof(sec));
    memset(f,0,sizeof(f));
    memset(dp,0,sizeof(dp));
    memset(up,0,sizeof(up));
    memset(cost,0,sizeof(cost));
}

int dfs(int u){
    int pre;//记录在子树上获得最大直径所通过的子结点
    int& res=dp[u];
    for(int i=0;i<next[u].size();i++){
        int v=next[u][i];
            int temp=dfs(v)+cost[v];
        if(res<temp){         //更新最大直径
            sec[u]=res;   
            res=temp; pre=v;
        }
        else if(temp>sec[u]){//更新次最大直径
            sec[u]=temp;
        }
    }
    f[u]=pre;
    return res;
}

void DP(int u){
    for(int i=0;i<next[u].size();i++){
        int v=next[u][i];
        if(f[u]==v){    //如果结点u通过其子结点v得到最大直径
            up[v]=Max(up[u],sec[u])+cost[v];
        }
        else{
            up[v]=Max(up[u],dp[u])+cost[v];
        }
        DP(v);
    }
}

int main(){
    while(~scanf("%d",&n)){
        init();
        for(int i=2;i<=n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            next[a].push_back(i);
            cost[i]=b;
        }
        dfs(1);        //计算每个结点到其子树上叶结点最大距离
        DP(1);         //更新最大距离
        for(int i=1;i<=n;i++){
            printf("%d\n",Max(dp[i],up[i]));//取向下和向上的最大值
        }
    }
}


原创粉丝点击