HDU 2196 树状DP


一开始看见这题很难,看了很久看不懂,后来仔细分析加具体模拟,可以发现此题非常巧妙


关键点在理解为什么要求出最远距离和次远距离,这在由父亲节点转移时会用到。仔细分析代码吧。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
#include<vector>
#include<map>
#include<iostream>
#include<string>
using namespace std;
#define maxn 10010
struct node
{
    int v,val;
};
int son[maxn];//从子树更新上来得到的最长距离
int father[maxn];//从父亲节点转移过来的最长距离
int far[maxn];//记录父节点从它开始得到的最长距离的边
int second[maxn];//如果有分支,则计算它的次长距离
vector<node> vec[maxn];
void init()//初始化
{
    for(int i=0;i<maxn;i++)
    vec[i].clear();
}
void down_dfs(int rt)//从根节点向下搜
{
    int sz=vec[rt].size();
    if(sz==0) return;
    int i,dir=-1,max_val=-1;
    for(i=0;i<sz;i++)   //向下递归到叶子节点,从叶子节点一层一层地返回,并同时找到次远距离
    {
        int v=vec[rt][i].v;
        down_dfs(v);
        if(son[v]+vec[rt][i].val>max_val)
        {
            max_val=son[v]+vec[rt][i].val;
            dir=i;
        }
    }
    son[rt]=max_val;
    far[rt]=dir;
    max_val=-1;
    int dir1=-1;
    for(i=0;i<sz;i++)//找次远距离
    {
        int v=vec[rt][i].v;
        if(i!=dir&&max_val<son[v]+vec[rt][i].val)
        {
          max_val=son[v]+vec[rt][i].val;
          dir1=i;
        }
    }
    if(dir1!=-1) //如果存在分支,当前节点只有一个分支,则次远距离为0
    second[rt]=max_val;
}
void up_dfs(int rt)//从父亲节点转移来的距离
{
    int sz=vec[rt].size();
    if(sz==0) return;
    int i;
    for(i=0;i<sz;i++)
    {
        int v=vec[rt][i].v;
        if(i==far[rt])//如果当前点在最远路径上,则由次远距离转移
        father[v]=max(second[rt],father[rt])+vec[rt][i].val;
        else   //如果当前点不在最远路径上,由最远距离转移
        father[v]=max(son[rt],father[rt])+vec[rt][i].val;
        up_dfs(v);
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    int n;
    while(scanf("%d",&n)==1)
    {
        init();
        int i;
        int a,val;
        for(i=2;i<=n;i++)
        {
            scanf("%d%d",&a,&val);
            node t;
            t.v=i;
            t.val=val;
            vec[a].push_back(t);
        }
        for(i=1;i<=n;i++)
        {
            son[i]=0;
            father[i]=0;
            second[i]=0;
        }
        down_dfs(1);
        up_dfs(1);
        for(i=1;i<=n;i++)
        printf("%d\n",max(son[i],father[i]));//由子树得到的最远距离和从父亲节点转移距离取最大
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值