A. The Fair Nut and the Best Path
题意:给定有点权,有边权的树,让你选择一条链(也可以是只有一个点),使得点权之和-边权最大。
思路:裸的树形DP,我们用dp[i]表示i的子树里某个点到i这条链的最大值,然后用次大值更新答案即可。
具体的,每个dp[i]初始化=a[i]; 对于i连出去的边-> (i,j),用它来更新答案,max(ans,dp[i]+dp[j]-len[i,j]);然后用它更新dp[i],max(dp[i],dp[i]-len[i,j]);
因为要的是最大值,肯定中途是大于等于0的,所以不会有中途油料耗尽的情况。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) #define ll long long using namespace std; const int maxn=1000010; int a[maxn],Laxt[maxn],Next[maxn],To[maxn],Len[maxn],cnt; ll dp[maxn],ans; void add(int u,int v,int c) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=c; } void dfs(int u,int f) { dp[u]=a[u]; if(a[u]>ans) ans=a[u]; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(v==f) continue; dfs(v,u); ans=max(ans,dp[u]+dp[v]-Len[i]); dp[u]=max(dp[u],dp[v]-Len[i]+a[u]); } } int main() { int N,u,v,c; scanf("%d",&N); rep(i,1,N) scanf("%d",&a[i]); rep(i,1,N-1){ scanf("%d%d%d",&u,&v,&c); add(u,v,c); add(v,u,c); } dfs(1,0); printf("%lld\n",ans); return 0; }