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

CF1388C Uncle Bogdan and Country Happiness 题解


CF1388C Uncle Bogdan and Country Happiness 题解

题目链接:CF1388C Uncle Bogdan and Country Happiness

题意

给出一颗根节点为 \(1\) 的树,对于每个节点 \(i\),有 \(p_i\) 个人的家在节点 \(i\) 上。

一开始所有人都在根节点上,然后每个人会往家沿着最短路走。

每个人出发时有一个心情,可能是好心情也可能是坏心情,在经过一条边时,心情可能由好变坏,但是不可能由坏变好。

每个点有一个幸福检测器,最后的检测结果为:所有经过该节点的人中,好心情的人数减坏心情的人数。

现在给出 \(h_i\),问有没有可能最后每个节点的检测结果恰好为 \(h_i\)

输入格式

第一行一个整数 \(t\) 表示有多少组数据。

每组数据中,第一行两个整数 \(n,m(1 \le n \le 10^5 , 0 \le m \le 10^9)\),表示节点数和总人数。

第二行 \(n\) 个整数表示 \(p_i(0 \le p_i \le m,\sum p_i = m)\)

第三行 \(n\) 个整数表示 \(h_i(-10^9 \le h_i \le 10^9)\)

下面 \(n-1\) 行,每行两个整数 \(x,y\),表示节点 \(x\)\(y\) 之间存在一条边。

输出格式

输出 \(t\) 行,每行为 YESNOYES 表示有可能最后每个节点的检测结果恰好为 \(h_i\)NO 表示没有可能。

就很细节题。考虑哪些情况合法。

  1. \(h_i\) 的绝对值不能超过 \(i\) 经过的总人数。
  2. 节点经过的人数一定为 \(2\) 的倍数。
  3. 节点经过的「心情不好的人数」一定不大于它『所有子节点经过的「心情不好的人数」之和』加上『在这个节点回家的人数』。

都很显然吧。实现的时候可以用个 pair<int,int> 来记录开心&不开心的人数。

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

代码:

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

int n,m,ok,a[N],b[N],k[N],h[N],p[N];
vector<int> vec[N];
pii dfs(int u,int f)
{
    if(!ok) return {0,0};
    pii p = {0, a[u]};
    for(int v : vec[u]) if(v != f)
    {
        pii tmp = dfs(v,u);
        p.Fi += tmp.Fi; p.Se += tmp.Se;
    }
    int x = p.Fi + p.Se + h[u];
    if(x & 1) { ok = 0; return {0,0}; }
    x /= 2;
    if(x < p.Fi || x > p.Fi + p.Se){ ok = 0; return {0,0}; }
    return pii(x, p.Fi + p.Se - x);
}
void work()
{
    cin >> n >> m;
    for(int i=1; i<=n; i++) { cin >> a[i]; vec[i].clear(); }
    for(int i=1; i<=n; i++) cin >> h[i];
    for(int i=1,u,v; i<n; i++)
    {
        cin >> u >> v;
        vec[u].push_back(v); vec[v].push_back(u);
    }
    ok = 1; dfs(1,0); cout << (ok ? "YES\n" : "NO\n");
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int _Q; cin >> _Q; while(_Q--) work();
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/80614/solution-cf1388c


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