Computer(hdu 2196)

题意:给出一棵树,求出每个点与距离它最远的点的距离。

/*
    树形DP 
    先把无根树转为有根树,对于一个节点i来说,与它相距最远的点有两种可能,一是在它的子树中,二是不在,我们分别用f[i][0]和f[i][1]来表示。
    f[i][0]很好求,从子节点向它的父亲递推就可以了。
    关键在于求f[i][1],我们发现f[i][1]可能有两种情况,一是来自它父亲的子树,而是来自它父亲的f[j][1],然后判断一下就好了。 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 10010
#define lon long long
using namespace std;
int head[N],vis[N],n,cnt;
lon f[N][2];
struct node{int v,w,pre;}e[N*2];
void add(int u,int v,int w){
    e[++cnt].v=v;e[cnt].w=w;e[cnt].pre=head[u];head[u]=cnt;
    e[++cnt].v=u;e[cnt].w=w;e[cnt].pre=head[v];head[v]=cnt;
}
lon dfs1(int u){
    vis[u]=1;
    for(int i=head[u];i;i=e[i].pre){
        if(vis[e[i].v]) continue;
        f[u][0]=max(f[u][0],dfs1(e[i].v)+e[i].w);
    }
    return f[u][0];
}
void dfs2(int u){
    vis[u]=1;
    lon max1=0,max2=0;int v1,v2;
    for(int i=head[u];i;i=e[i].pre){
        int v=e[i].v,w=e[i].w;
        if(vis[v]) continue;
        if(f[v][0]+w>max1){
            max2=max1;v2=v1;
            max1=f[v][0]+w;v1=v;
        }
        else if(f[v][0]+w>max2){
            max2=f[v][0]+w;v2=v;
        }
    }
    if(u!=1){
        if(f[u][1]>max1){
            max2=max1;v2=v1;
            max1=f[u][1];v1=-1;
        }
        else if(f[u][1]>max2){
            max2=f[u][1];v2=-1;
        }
    }
    for(int i=head[u];i;i=e[i].pre){
        int v=e[i].v;
        if(vis[v]) continue;
        if(v1!=v) f[v][1]=max1+e[i].w;
        else f[v][1]=max2+e[i].w;
        dfs2(e[i].v);
    }
}
void work(){
    for(int u=2;u<=n;u++){
        int v,w;scanf("%d%d",&v,&w);
        add(u,v,w);
    }
    memset(vis,0,sizeof(vis));
    dfs1(1);
    memset(vis,0,sizeof(vis));
    dfs2(1);
    for(int i=1;i<=n;i++)
        cout<<max(f[i][0],f[i][1])<<endl;
}
int main(){
    freopen("jh.in","r",stdin);
    while(scanf("%d",&n)!=EOF){
        memset(head,0,sizeof(head));
        memset(f,0,sizeof(f));
        cnt=0;
        work();
    }
    return 0;
}

 

posted @ 2017-04-19 22:25  karles~  阅读(187)  评论(0编辑  收藏  举报