嘘~ 正在从服务器偷取页面 . . .

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


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

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

题意

给定一棵树,根节点为 $1$ ,有点权 $w_i$ ,cxy 想在在结点上放满梅花。

她从这棵树的 $1$ 号节点出发,沿着树上的边行走。

设当前在 $u$ ,则 cxy 每次只能走到一个没有走过的儿子结点 $v$ ,或者回到 $u$ 的父亲。

当且仅当一个结点 $u$ 的所有儿子 $v$ 都放满了 $w_v$ 朵,才可以在 $u$ 上放置梅花。

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

数据范围

$1 \leq n \leq 10^5 + 4,~1 \leq w_i \leq 1000$。

设第 $i$ 个结点放梅花的最小花费为 $f_i$ ,不难发现

后者是最小花费的下界

观察第一部分

这部分显然与 $\text{son}(u)$ 的排列有关

如何求出这个最优排列?

贪心,按 $g_u = f_u - w_u$ 降序排序即可

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

设 $x$ 在 $y$ 之前更优,则

  • 若 $f_y + w_x \ge f_x$ ,

    因为 $f_y + w_x > f_y$ ,所以右侧取 $f_x+w_y$ 才可能成立

    则可得

    移项得

  • 若 $f_y + w_x < f_x$

    则 $f_x > f_y$,故右侧取 $f_x+w_y$ 时才可能成立

    显然有 $f_x < f_x + w_y$

综上所述,按 $g_u = f_u - w_u$ 降序排序可以获得最优解

时间复杂度 $\mathcal{O}(n \log n)$

代码:

#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;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录