Codeforces Round #660 (Div. 2) C(dfs)

https://codeforces.com/contest/1388/problem/C
在这里插入图片描述
在这里插入图片描述

题意

给定n个节点的树结构,m个人初始在根节点1号,已知每个人都有各自要到达的节点(默认走最短路),他们刚出发有各自的心情状态(好/坏)且我们未知,在节点之间的转移过程中好心情会转化为坏心情,但心情坏的不会发生改变。先给定每个节点数据h[i],理论上值为该节点上 心情好的人数 - 心情坏的人数,现要判断给定数据是否正确。

思路

设经过城市 u u u的好心情人数为: g [ u ] g[u] g[u],拜访城市 u u u的总人数为: a [ u ] a[u] a[u],城市 u u u检测到的最终心情值为 h [ u ] h[u] h[u]
g [ u ] g[u] g[u]可由此推出: g [ u ] − ( a [ u ] − g [ u ] ) = h [ u ] → g [ u ] = ( a [ u ] + h [ u ] ) / 2 g[u]−(a[u]−g[u])=h[u]→g[u]=(a[u]+h[u]) / 2 g[u](a[u]g[u])=h[u]g[u]=(a[u]+h[u])/2
其中:

  1. 2 2 2能整除 ( a [ u ] + h [ u ] ) (a[u]+h[u]) (a[u]+h[u])
  2. g [ u ] ∈ [ 0 , a [ u ] ] g[u]∈[0,a[u]] g[u][0,a[u]] :因为好心情人数不可能超过总人数
  3. g [ u ] ≥ ∑ v ∈ s o n g [ v ] g[u]≥\displaystyle\sum_{v∈son}g[v] g[u]vsong[v] :父节点的好心情肯定大于等于子节点的好心情总和

d f s dfs dfs 从节点 1 1 1 跑一遍树,用变量 s u m sum sum记录子节点的总好心情,结束访问后判断上面三个条件。

代码

#include<bits/stdc++.h>
#define ios std::ios::sync_with_stdio(false) , std::cin.tie(0) , std::cout.tie(0)
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
int n,m,p[N],u,v,flag;
int a[N],h[N],g[N];
vector<int>e[N];
void dfs(int u,int fa)
{
	a[u] = p[u];
	int sum = 0;
	for(auto v:e[u]){
		if (v == fa) continue;
		dfs(v,u);
		sum += g[v];
		a[u] += a[v];
	}
	if ((a[u] + h[u])&1) {flag = 0; return;}
	g[u] = (a[u] + h[u]) >> 1;
	if (g[u] < 0 || g[u] > a[u]) {flag = 0; return;}
	if (sum > g[u]) {flag = 0; return;}
}
signed main()
{
	ios;
	int T;
	cin >> T;
	while (T--)
	{
		cin >> n >> m;	
		rep(i,1,n)	cin >> p[i];
		rep(i,1,n)  cin >> h[i];
		rep(i,1,n-1){
			cin >> u >> v;
			e[u].pb(v); 
			e[v].pb(u);
		}
		flag = 1;
		dfs(1,0);
		if (flag) puts("YES");
		else puts("NO");
		rep(i,1,n) e[i].clear();
	} 
    return 0;
}

参考博客:https://blog.csdn.net/weixin_45750972/article/details/107706065

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值