洛谷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 1≤n≤105+4, 1≤wi≤1000。
设第
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=max⎩⎨⎧v∈son(u)max⎩⎨⎧fv+k∈son(u)∧k before v∑wk⎭⎬⎫,wu+v∈son(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\}
v∈son(u)max⎩⎨⎧fv+k∈son(u)∧k before v∑wk⎭⎬⎫
这部分显然与
son
(
u
)
\text{son}(u)
son(u) 的排列有关
如何求出这个最优排列?
贪心,按 g u = f u − w u g_u = f_u - w_u gu=fu−wu 降序排序即可
考虑 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+wx≥fx ,
因为 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+wx≤fx+wy
移项得
f x − w x ≤ f y − w y f_x-w_x \le f_y-w_y fx−wx≤fy−wy -
若 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=fu−wu 降序排序可以获得最优解
时间复杂度 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;
}
转载请说明出处