D. The Fair Nut and the Best Path
题目链接:https://codeforces.com/contest/1084/problem/D
题意:
给出一棵树,走不重复的路径,每到一个结点加上其权值,经过一条边减去其权值,路径中途减去后不能出现负数,问怎么选择路径可以让最后得到的最大。
题解:
这题考虑用dp来做。
我们定义dp[u]为走到u点的最大值,注意这里的方向,是走到u点。题目中的意思是路径不能走回头路。
对于一个父节点u,那么我们可以根据走到其儿子结点的最大值来更新经过父节点的路径的最大值。
如果两个儿子到u(dp[v1]+dp[v2]-dis(v1,u)-dis(v2,u))都为正数,那么此时ans = a[u]+dp[v1]+dp[v2]-dis(v1,u)-dis(v2,u)。在这里虽然dp指的是走到当前结点的最大值,但是反过来走并不影响其结果。
具体做法就是每次根据其儿子维护经过当前结点的最大值,在最后根据其儿子选择一个较大值更新当前结点的dp值。
这题要用大最大连续子段和的技巧...
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 3e5+5; int n; ll a[N],dp[N]; ll ans; vector <pair<int,int> > g[N]; void dfs(int node,int pa){ ans=max(ans,a[node]); ll mx=0; for(auto v:g[node]){ if(v.first==pa) continue ; dfs(v.first,node); ans=max(ans,mx+dp[v.first]-v.second+a[node]); mx=max(mx,dp[v.first]-v.second); } dp[node]=mx+a[node]; return ; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%I64d",&a[i]); } for(int i=1;i<n;i++){ int u,v,c; scanf("%d%d%d",&u,&v,&c); g[u].push_back(make_pair(v,c)); g[v].push_back(make_pair(u,c)); } dfs(1,-1); cout<<ans<<endl; return 0; }
原文地址:https://www.cnblogs.com/heyuhhh/p/10116517.html
时间: 2024-11-10 08:23:49