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

47 篇文章 0 订阅
7 篇文章 0 订阅

D. The Fair Nut and the Best Path

题意

给你一棵树,在树中找出一条路径(也可以只有一个点),
这条路径(点权和-边权和)最大。

做法

我们设dp[i]为以i为出发点向子树方向的最优路径,
那么我们可以很轻松的用儿子的dp数组更新父亲的dp数组
也就是取一个最大的dp[i]-w[v],w[v]表示父亲与这个儿子之间的路径权值

我们有了dp数组,我们发现,对于某个点,如果答案在这个点的子树内而且经过这个点,答案要么是从这个点出发的一条向子树的路径,要么是从某个子树到这个点再到另一颗子树。对于第一种情况,答案很显然就是dp[i]中的最大值,第二种情况,就对每个点在他的儿子中选两个最优的连接起来,同样取所有点的最大值就可以。
在这里插入图片描述
比如上图,经过rt的而且在他的子树内的最优路径,一定是在所有的 D P [ i ] − w i DP[i]-w_i DP[i]wi中选出两个最大而且大于0的值,连接起来。就这样不断从叶子向上更新就可以得到答案。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5+5;
vector<int> G[maxn];
vector<ll> val[maxn];
ll w[maxn];
ll dp[maxn];
int n,u,v;
ll we,ans;
vector<ll> tmp;
bool cmp(ll a,ll b)
{
    return a>b;
}
void dfs(int rt,int fa)
{
    dp[rt]=w[rt];
    for(int i=0;i<G[rt].size();i++)
    {
        int to=G[rt][i];
        ll va=val[rt][i];
        if(to==fa) continue ;
        dfs(to,rt);
        dp[rt]=max(dp[rt],w[rt]+dp[to]-va);
    }
    ans=max(ans,dp[rt]);
    tmp.clear();
    for(int i=0;i<G[rt].size();i++)
    {
        int to=G[rt][i];
        ll va=val[rt][i];
        if(to==fa) continue ;
        tmp.push_back(dp[to]-va);
    }
    sort(tmp.begin(),tmp.end(),cmp);
    ll tt=w[rt];
    if(tmp.size()>=2)
    {
        if(tmp[0]>=0) tt+=tmp[0];
        if(tmp[1]>=0) tt+=tmp[1];
    }
    ans=max(ans,tt);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d%lld",&u,&v,&we);
        G[u].push_back(v);
        G[v].push_back(u);
        val[u].push_back(we);
        val[v].push_back(we);
    }
    dfs(1,-1);
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值