树的直径 树形dp+2次dfs


 

题目描述

给定一棵树 T ,树 T 上每个点都有一个权值。

定义一颗树的子链的大小为:这个子链上所有结点的权值和 。

请在树 T 中找出一条最大的子链并输出。

输入描述:

 
 

第一行输入一个 n,1≤n≤105。

接下来一行包含n个数,对于每个数 ai,−10^5≤ai≤10^5,表示 i 结点的权值。

接下来有n-1行,每一行包含两个数u,v( 1≤u,v≤n , u != v),表示u与v之间有一条边。

输出描述:

 
 

仅包含一个数,表示我们所需要的答案。

示例1

输入

5
2 -1 -1 -2 3
1 2
2 3
2 4
2 5

输出

4

说明

样例中最大子链为1 -> 2 -> 5

备注:

一个结点,也可以称作一条链

 树形dp:

如果值在边上的话

void DP(int u,int pa)
{
    dp[u]=0;
    for(int i=h[u];i;i=ne[i])
    {
        int v=e[i];
        if(v==pa) continue;
        DP(v,u);
        ans=max(ans,dp[u]+dp[v]+dis[i]);
        dp[u]=max(dp[u],dp[v]+dis[i]);
    }
}

如果值在点上的话

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int N=1e5+10;
int n;
ll idx,e[N*2],h[N],ne[2*N],w[N],dp[N],ans;
bool vis[N];
void add(int x,int y)
{
    e[idx]=y;
    ne[idx]=h[x];
    h[x]=idx++;
}
void dfs(int x)
{
    dp[x]=w[x];
    vis[x]=1;
    ans=max(ans,w[x]);
    for(int i=h[x]; ~i; i=ne[i])
    {
        int j=e[i];
        if(vis[j])continue;
        dfs(j);
        ans=max(ans,dp[x]+dp[j]);
        dp[x]=max(dp[x],dp[j]+w[x]);
    }
}
int  main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    memset(h,-1,sizeof h);
    ans=-INF;
    for(int i=1; i<=n; i++)
    {
        cin>>w[i];
    }
    for(int i=1; i<=n-1; i++)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    dfs(1);
    cout<<ans;
    return 0;
}

两次dfs

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF =0x3f3f3f3f;
const int N=1e5+10;
int n,pos;
ll idx,e[N*2],h[N],ne[2*N],w[N],dp[N],ans;
bool vis[N];
void add(int x,int y)
{
    e[idx]=y;
    ne[idx]=h[x];
    h[x]=idx++;
}
void dfs(int now,ll x)
{
    vis[now]=1;
    if(ans<x)
    {
        ans=x;
        pos=now;
    }
    for(int i=h[now]; ~i; i=ne[i])
    {
        int j=e[i];
        if(vis[j])continue;
        dfs(j,x+w[j]);
    }
}
int  main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    memset(h,-1,sizeof h);
    ans=-INF;
    for(int i=1; i<=n; i++)
    {
        cin>>w[i];
    }
    for(int i=1; i<=n-1; i++)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    dfs(1,w[1]);
    //cout<<ans;
    memset(vis,0,sizeof vis);
    dfs(pos,w[pos]);
    cout<<ans;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值