https://codeforces.com/problemset/problem/1083/A
题意:到达一个点得到这个点的价值,经过一个边花费这个边的价值,求得到的最大价值
思路:之前碰过一些无根树的问题,有些是直接定1为根就可以了不用考虑其他,但是有些不行。比如树的重心,一种方法是定1为根然后考虑dp转移过程中该节点“头上”的量。比如树的直径,确实可以两次dfs求,树形dp的求法也是类似考虑节点“头上”的量。
这题是个无根树,考虑头上的量。
先考虑以u为根节点的子树,
1.u是起点,那么就是u在子树中所能获得的最大价值
2.u是转折点,那么就是u在子树中获得的最大价值与次大价值之和
这个转折点的意思是,出现了一个类似倒V形状,注意这道题的一个要求是路径是简单路径,也就是没有重边和自环
然后考虑u通过父亲所能获得的最大价值与u在子树中所能获得的最大价值之和
类似树的直径问题。
这里注意通过fa[u]获得的最大价值,是不会以u作为转折点获得的,因为转折点的话就已经完成了简单路径,要走上去的话要回走一条重边。
然后发现 u通过父亲fa所能获得的最大价值与u在子树中所能获得的最大价值之和 其实已经被
以fa为转折点(我的理解)在子树中所能获得的最大价值 所包括
而在dp的转移中,用dp[]维护的是u为起点的最大价值,怎么取u为转折点呢?用一个ans去维护ans=max(ans,dp[u]+dp[v]-cost);
这个ans的右边的值就是一个倒V的值,取且只能取一个最大的。
dp的转移也是转移以u为起点的最大价值,是一条直着的路径,不会转折。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=3e5+100;
typedef long long LL;
LL val[maxn],dp[maxn],ans;
vector< pair<LL,LL> >g[maxn];
void dfs(LL u,LL fa)
{
dp[u]=val[u];
ans=max(ans,dp[u]);
for(LL i=0;i<g[u].size();i++)
{
LL v=g[u][i].first;
LL w=g[u][i].second;
if(v==fa) continue;
dfs(v,u);
ans=max(ans,dp[u]+dp[v]-w);
dp[u]=max(dp[u],dp[v]+val[u]-w);
}
}
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL n;cin>>n;
for(LL i=1;i<=n;i++) cin>>val[i];
for(LL i=1;i<n;i++){
LL x,y,w;cin>>x>>y>>w;
g[x].push_back({y,w});
g[y].push_back({x,w});
}
dfs(1,0);
cout<<ans<<endl;
return 0;
}