Codeforces Round #526 (Div. 2) D. The Fair Nut and the Best Path 树形dp

题目链接:

传送门


题意:

每个点有正权值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;
}

猜你喜欢

转载自blog.csdn.net/qq_41410799/article/details/85131379