题目链接
题意:给定n个点的树,树上每个点都有点权,每条边有边权,要求找出树上的两个点,两点间点权之和减去边权之和最大。
思路:第一遍dfs先求u的子树到u的最大值,第二遍dfs看看除了子树以外的边能否更新最大值,这里要注意一下子树中两点的和,其实我这个做法有点多余了,好像只要记录u的子树的最大值和次大值就可以了。。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=3e5+5;
vector<pair<int,ll>>g[maxn];
ll ans=0,w,dp[maxn],a[maxn];
map<int,int>p;
void dfs(int x,int fa)
{
dp[x]=a[x];
ll max1=0,max2=0;
for(auto to:g[x])
{
if(to.first==fa) continue;
dfs(to.first,x);
if(dp[x]<dp[to.first]+a[x]-to.second) dp[x]=dp[to.first]+a[x]-to.second,max1=dp[x],p[x]=to.first;
else if(dp[x]==dp[to.first]+a[x]-to.second) max2=max1;
else if(max2<dp[to.first]+a[x]-to.second) max2=dp[to.first]+a[x]-to.second;
}
ans=max(ans,max1+max2-a[x]);
}
void dfs2(int x,int fa,ll t)
{
if(p[fa]!=x)
{
if(dp[x]<dp[fa]+a[x]-t) dp[x]=dp[fa]+a[x]-t,p[x]=fa;
}
for(auto to:g[x])
{
if(to.first==fa) continue;
dfs2(to.first,x,to.second);
}
}
int main()
{
int n,u,v;
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
for(int i=1;i<n;++i)
{
scanf("%d %d %lld",&u,&v,&w);
g[u].push_back({v,w});
g[v].push_back({u,w});
}
dfs(1,0);
dfs2(1,0,0);
for(int i=1;i<=n;++i) ans=max(ans,dp[i]);
printf("%lld\n",ans);
}