洛谷P5521 [yLOI2019] 梅深不见冬 题解

洛谷P5521 [yLOI2019] 梅深不见冬 题解

题目链接:P5521 [yLOI2019] 梅深不见冬

题意

给定一棵树,根节点为 1 1 1 ,有点权 w i w_i wi ,在结点上放满梅花

放的要求是,只有一个结点 u u u所有儿子 v v v 都放满了 w v w_v wv 梅花才可以放

梅花可以随时收回,求每个结点放梅花的最小花费


这个背景蛮有趣的,留着(逃

风,吹起梅岭的深冬;霜,如惊涛一样汹涌;
雪,飘落后把所有烧成空,像这场,捕捉不到的梦。
醒来时已是多年之久,宫门铜环才长了铁锈,也开始生出离愁。

——银临《梅深不见冬》

1 ≤ n ≤ 1 0 5 + 4 ,   1 ≤ w i ≤ 1000 1 \leq n \leq 10^5 + 4,~1 \leq w_i \leq 1000 1n105+4, 1wi1000

设第 i i i 个结点放梅花的最小花费为 f i f_i fi ,不难发现
f u = max ⁡ { max ⁡ v ∈ son(u) { f v + ∑ k ∈ son ( u )   ∧   k  before  v w k } , w u + ∑ v ∈ son ( u ) w v } f_u = \max\left\{ \max_{v \in \text{son(u)}} \left\{f_v + \sum_{k \in \text{son}(u)\, \land \,k \text{ before } v} w_k\right\},w_u + \sum_{v \in \text{son}(u)}w_v\right\} fu=maxvson(u)maxfv+kson(u)k before vwk,wu+vson(u)wv
后者是最小花费的下界

观察第一部分
max ⁡ v ∈ son(u) { f v + ∑ k ∈ son ( u )   ∧   k  before  v w k } \max_{v \in \text{son(u)}} \left\{f_v + \sum_{k \in \text{son}(u)\, \land \,k \text{ before } v} w_k\right\} vson(u)maxfv+kson(u)k before vwk
这部分显然与 son ( u ) \text{son}(u) son(u) 的排列有关

如何求出这个最优排列?

贪心,按 g u = f u − w u g_u = f_u - w_u gu=fuwu 降序排序即可

考虑 u u u 仅有 2 2 2 个子结点 x , y x,y x,y 的情况,

x x x y y y 之前更优,则
f u = max ⁡ { f x , f y + w x } ≤ max ⁡ { f y , f x + w y } f_u=\max\{f_x,f_y+w_x\}\le \max\{f_y,f_x+w_y\} fu=max{fx,fy+wx}max{fy,fx+wy}

  • f y + w x ≥ f x f_y + w_x \ge f_x fy+wxfx

    因为 f y + w x > f y f_y + w_x > f_y fy+wx>fy ,所以右侧取 f x + w y f_x+w_y fx+wy 才可能成立

    则可得
    f y + w x ≤ f x + w y f_y + w_x \le f_x + w_y fy+wxfx+wy
    移项得
    f x − w x ≤ f y − w y f_x-w_x \le f_y-w_y fxwxfywy

  • f y + w x < f x f_y + w_x < f_x fy+wx<fx

    f x > f y f_x > f_y fx>fy,故右侧取 f x + w y f_x+w_y fx+wy 时才可能成立

    显然有 f x < f x + w y f_x < f_x + w_y fx<fx+wy

综上所述,按 g u = f u − w u g_u = f_u - w_u gu=fuwu 降序排序可以获得最优解

时间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iomanip>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e5+15)

vector<int> son[N];
int n,m,w[N],f[N];
int cmp(int x,int y)
{return f[y]-w[y]<f[x]-w[x];}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n;
    for(int i=2,u; i<=n; i++)
        cin >> u,son[u].push_back(i);
    for(int i=1; i<=n; i++) cin >> w[i];
    for(int i=n; i>=1; i--)
    {
        sort(son[i].begin(),son[i].end(),cmp);
        int sum=0;
        for(int v : son[i])
            f[i]=max(f[i],f[v]+sum),sum+=w[v];
        f[i]=max(f[i],sum+w[i]);
    }
    for(int i=1; i<=n; i++)
        cout << f[i] << " \n"[i==n];
    return 0;
}

转载请说明出处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值