树上子链 -树的直径

本文介绍了如何使用树形动态规划解决ACM问题,通过两次DFS遍历优化找到一棵树中边权和最大的链。方法核心在于维护每个节点的边扩展带来的最大值和次大值,仅需一次遍历即可求解。博主详细展示了C++代码实现并解释了算法原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

链接:https://ac.nowcoder.com/acm/problem/202475
来源:牛客网

输入
复制
5
2 -1 -1 -2 3
1 2
2 3
2 4
2 5
输出
复制
4
说明
样例中最大子链为1 -> 2 -> 5

相当于是在一棵树中找到一条边权和最大的链
有一种方法是:跑两遍dfs,第一遍取任意一点找到最长的链,取 链中离选取点最远的点再跑一遍dfs即可,但是此方法无法处理负边权。因此我是用第二种方法:树形DP
第二种方法:
任取一个点,找到这个边延伸到的所有点的最大值和次大值来更新ans。为什么找最大值和次大值呢,因为最大值+次大值+当前点权值便可以组成最大边权链
因此我们只需要做一遍深度优先遍历,任意去一个点做深搜,深搜函数的返回值是以当前为根节点的权值最大的链,因此在深搜的过程中,不断地维护最大值和次大值即可

#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define int long long

int e[2*N],ne[2*N],w[N],h[N],idx=0;
int n,root;
int val[N];
int ans=-0x3f3f3f3f;

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int dfs(int u,int pre){
    int t=-0x3f3f3f3f;
    int mx=0,mx2=0;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==pre) continue;
        int res=dfs(j,u);
        if(res>mx){
            mx2=mx,mx=res;
        }
        else if(res>mx2) mx2=res;
    }
    ans=max(ans,mx+mx2+val[u]);
    return mx+val[u];
}

signed main(){
    memset(h,-1,sizeof h);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&val[i]);
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%lld%lld",&a,&b);
        add(a,b),add(b,a);
    }
    
    dfs(1,-1);
    
    printf("%lld\n",ans);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值