sgu 149


两次树形dp,
第一次是求出 f(i) 以i为根的子树中的结点到i点的 最远距离和次远距离
第二次是求出 g(i) 以i为根的子树外的结点到i点的 最远距离

转移方程并不复杂哦~,最后 ans(i)=max(f(i),g(i))


#include<map>
#include<stack>
#include<queue>
#include<utility>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<iostream>
#include<algorithm>

#define Mp(x,y) std::make_pair(x,y)
#define Max1 first
#define Max2 second

const int MAXN = 10005;

int n;
struct Edge
{
    int v,w,next; 
    Edge(int v = 0,int w = 0,int next = 0):v(v),w(w),next(next){};

}edge[MAXN<<1];
int el = 0, head[MAXN] = {0};

std::pair<int,int>f[MAXN];  
int g[MAXN] = {0};

void NewEdge(int u,int v,int w){++el; edge[el] = Edge(v,w,head[u]); head[u] = el;}  

namespace SonSolve
{
    void DFS(int a,int fa)
    {
        for(int i = head[a]; i ; i = edge[i].next)
        {
            int p = edge[i].v;
            if(p == fa) continue;

            DFS(p , a);

            int tmp = f[p].Max1 + edge[i].w;

            if(tmp >= f[a].Max1)     
                f[a] = Mp(tmp,f[a].Max1);
            else if(tmp > f[a].Max2) 
                f[a].Max2 = tmp;
            else;       
        }   
    }   
}
namespace FaSolve
{
    void DFS(int a,int fa)
    {
        for(int i = head[a]; i ; i = edge[i].next)
        {
            int p = edge[i].v;
            if(p == fa) continue;

            int tmp = (f[p].Max1 + edge[i].w == f[a].Max1)?f[a].Max2:f[a].Max1;

            g[p] = std::max(g[a], tmp) + edge[i].w;

            DFS(p , a);
        }
    }
}   

int main()
{
#ifndef ONLINE_JUDGE
    freopen("sgu149.in","r",stdin);
    freopen("sgu149.out","w",stdout);
#endif

    std::cin >> n; 
    for(int i = 2, to, len; i <= n; i++)
    {
        scanf("%d%d",&to,&len);
        NewEdge(to,i,len);
        NewEdge(i,to,len);
    }   

    SonSolve::DFS(1,0);
    FaSolve::DFS(1,0);

    for(int i = 1; i <= n; i++)
        printf("%d\n",std::max(f[i].Max1,g[i]));

    fprintf(stderr,"%f",clock()*1.0/CLOCKS_PER_SEC);
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
#endif
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值