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

CF846E Chemistry in Berland 题解


CF846E Chemistry in Berland 题解

题目链接:CF846E Chemistry in Berland

题意

cxy 是 Berland 大学化学系的研究生。她需要进行一个复杂的实验来撰写她的论文,但是 Berland 的实验室并没有包含这个实验所需要的所有材料。

幸运的是,化学法则允许物质之间的转化(不过 Berland 的化学与我们的不同),但是物质转化的规则有点奇怪。

Berland 化学家知道 \(n\) 种材料,按照某种顺序编号为 \(1, 2, \cdots, n\)。每种材料都可以与其它一种材料互相转化。正式地,对任意 \(2 \leq i \leq n\),都存在两个正整数 \(x_i, k_i\) 表示一种合理的转化:\(k_i \, \mathrm{kg}\) 的材料 \(x_i\) 可以转化成 \(1 \, \mathrm{kg}\) 的材料 \(i\),而 \(1 \, \mathrm{kg}\) 的材料 \(i\) 只能变成 \(1 \, \mathrm{kg}\) 的材料 \(x_i\)

由于 Berland 的化学系统比较奇怪,因此转化只允许整数质量的材料

对每个 \(1 \leq i \leq n\),cxy 知道她的实验中需要 \(a_i \, \mathrm{kg}\) 的材料 \(i\),且实验室中只有 \(b_i \, \mathrm{kg}\)。她想知道,是否存在一种转化方案,使得最终实验能够顺利进行?

输入格式

第一行包含一个正整数 \(n~(n \leq 10^5)\),表示 Berland 化学家发现的材料的数量。

第二行包含 \(n\) 个正整数 \(b_1, b_2, \cdots, b_n~(b_i \leq 10^{12})\),表示 Berland 实验室的供应。

第三行包含 \(n\) 个正整数 \(a_1, a_2, \cdots, a_n~(a_i \leq 10^{12})\),表示实验所需(各种物质的)的质量。

接下来的 \(n-1\) 行,每行包含两个正整数,其中第 \(i\) 行的整数 \(x_{i+1}, k_{i+1}~(1 \leq x_{i+1} \leq i, k_{i+1} \leq 10^9)\) 表示物质 \(i+1\) 可以与物质 \(x_{i+1}\) 相互转化,且转化系数为 \(k_{i+1}\)\(k_i\) 的含义见题目描述)。

输出格式

输出 YES 如果实验可以进行,否则输出 NO

注意到这是一棵树,因此考虑树形dp。

\(f_i\) 表示 \(i\) 所在子树ok之后,材料 \(i\) 还能剩多少(负的说明欠了)。显然叶子结点有 \(f_i = b_i - a_i\)

考虑转移。对于 \(u\) 的儿子 \(v \in \mathtt{son}(u)\) ,我们考虑以下几种情况:

  • \(f_v \ge 0\) 。显然此时 \(v\) 所在子树多出来的都可以给 \(u\)f[u] += f[v]
  • \(f_v < 0\) 。此时只能把 \(u\) 的材料给 \(v\) 。注意是 f[u] += k[v] * f[v]

最后只要看看是否有 \(f_1>0\) 即可。然后你会发现这题其实是个贪心。

有趣的是这个算的过程中会爆 long long

解决办法,要么开 long double ,要么在小于 -INF 时直接让 f[u] = -INF

后者正确的原因在于 \(f_i\) 增加的速度远低于其减少的速率,因此在 \(f_i\) 极小时基本上是无解的。

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

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5+15))

int n,pos=1,f[N],a[N],k[N],b[N],limit[N],head[N];
struct Edge{ int u,v,next; } e[N];
void addEdge(int u,int v) { e[++pos]={u,v,head[u]}; head[u]=pos; }
void dfs(int u)
{
    f[u] = b[u] - a[u];
    for(int i=head[u]; i; i=e[i].next)
    {
        int v = e[i].v; dfs(v);
        if(f[v] >= 0) f[u] += f[v];
        else (f[v] <= -limit[v]) ? (f[u] = -INF) : (f[u] += f[v] * k[v]);
        f[u] < -INF ? f[u] = -INF : 0;
    }
}
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=1; i<=n; i++) cin >> b[i];
    for(int i=1; i<=n; i++) cin >> a[i];
    for(int i=2,fa; i<=n; i++)
    {
        cin >> fa >> k[i];
        addEdge(fa,i); limit[i] = INF / k[i];
    }
    dfs(1);
    cout << ((f[1] < 0) ? "NO\n" : "YES\n");
    return 0;
}

参考文献

[1] https://yhx-12243.github.io/OI-transit/?redirect=240


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