Codeforces Round #526 (Div. 2) D. The Fair Nut and the Best Path 樹形dp
阿新 • • 發佈:2018-12-31
題目連結:
題意:
每個點有正權值ai,每條邊有負權值wi,你可以隨意選擇一條路徑,使得這條路徑的總權值最大,要求每個點每條邊至多都只能走一次。
思路:
一個頂點可以是路徑中的根節點或者是中間節點。
所以,設立兩個陣列,dpr,dpm.
dpr表示為根節點的最大權值。
dpm表示為中間節點的最大權值。
(1)為根節點
dpr[u]=w[u]+dpr[v]-edge<u,v>;
(2)為中間節點
求出其中與其相連的兩個節點,分別為最大值和次大值.
dpm[u]=w[u]+dpr[v1]-edge<u,v1>+dpr[v2]-edge<u,v2>;
然後求出最大值即可。
程式碼如下:
#include <bits/stdc++.h> using namespace std; const int maxn=3*1e5+5; typedef long long ll; ll w[maxn]; int n; int head[maxn]; ll dpr[maxn]; ll dpm[maxn]; ll ans=-1; struct edge { int to; int next; ll len; }; edge e[maxn*2]; void addedge(int v,int u,int id,ll len) { e[id].to=v; e[id].len=len; e[id].next=head[u]; head[u]=id; } void init() { for (int i=1;i<=n;i++) { dpm[i]=dpr[i]=w[i]; } } void dfs(int now,int pre) { ll mx,mm; mx=mm=0; for (int i=head[now];i!=-1;i=e[i].next) { int v=e[i].to; if(pre==v) continue; dfs(v,now); if(dpr[v]-e[i].len>mx) { mm=mx; mx=dpr[v]-e[i].len; } else if(dpr[v]-e[i].len>mm) { mm=dpr[v]-e[i].len; } } dpm[now]+=mm+mx; dpr[now]+=mx; ans=max(dpm[now],ans); ans=max(dpr[now],ans); } int main() { memset (head,-1,sizeof(head)); scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%lld",&w[i]); } for (int i=0,id=0;i<n-1;i++) { int x,y; ll len; scanf("%d%d%lld",&x,&y,&len); addedge(y,x,id++,len); addedge(x,y,id++,len); } init(); dfs(1,0); printf("%lld\n",ans); return 0; }