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$ 行,每行为
YES
或NO
,YES
表示有可能最后每个节点的检测结果恰好为 $h_i$,NO
表示没有可能。
就很细节题。考虑哪些情况合法。
- $h_i$ 的绝对值不能超过 $i$ 经过的总人数。
- 节点经过的人数一定为 $2$ 的倍数。
- 节点经过的「心情不好的人数」一定不大于它『所有子节点经过的「心情不好的人数」之和』加上『在这个节点回家的人数』。
都很显然吧。实现的时候可以用个 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;
}
参考文献: