题目链接:
题意:
每个点有正权值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;
}