链接: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;
}