AGC010C Cleaning

Description

传送门


Solution

考虑对于每个点处理它的所有儿子,它的所有儿子连上来的路径要不就是在当前子树内两两匹配,要不就是继续连到该点的父亲。

如果在子树内匹配,儿子两个儿子的石子数量减一,该节点的石子数量减一;对于连上去的,某个儿子的石子数量减一,该节点的石子数量减一。

所以设某节点处理完子树之后还要往父亲连(f_x)条路径,有(y)条路径在它的子树内互相匹配,它的子树内一共有(sum)条路径,它本身权值为(a_x),那么有

[y imes 2 + f_x = sum ]

[y + f_x = a_x ]

解得

[y = sum - a_x, f_x = sum - 2 imes y ]

首先连上去的路径个数肯定不能超过它本身的权值(a_x),即(f_x <= a_x);也不能是负数,即(f_x >= 0)

其次它的子树内部最多的两两互相匹配的路径个数要比需要的两两匹配的路径条数多,而这个最大值就是(max(frac{sum}{2}, sum - max_{f_v})),首先两两匹配最多就是(frac{sum}{2}),其次每个点不能和自己匹配所以还要和(sum - max_{f_v})取较小值。

注意(f_{root})必须是零,因为根节点不能再往上传递了。

注意到(n = 2)两个点都是叶子节点要特判。


Code

/*
    _______                       ________                        _______
   / _____                      / ______                       / _____ 
  / /     \_  _     __     _   / /          _     __     _   / /     \_
 | |          | |   |  |   | | | |        | | | |   |  |   | | | |
 | |          | |   |  |   | | | |     __ | | | |   |  |   | | | |
 | |       __     |  |  /  / | |      | |     |  |  /  / | |       __
   \_____/ /    / / /  /    \_____  /     / / /  /    \_____/ /
   \_______/    \___/  \___/     \______/\__   \___/  \___/     \_______/
*/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 1e5;

int head[N + 50], num, a[N + 50], f[N + 50], n, root, in[N + 50], flag = 1;

struct Node{
	int next, to;
} edge[N * 2 + 50];

void Addedge(int u, int v){
	edge[++num] = (Node){head[u], v};
	head[u] = num;
	return;
}

void Dfs(int x, int fa){
	if (in[x] == 1) { f[x] = a[x]; return; }
	int sum = 0, maxx = 0;
	for (int i = head[x]; i && flag; i = edge[i].next){
		int v = edge[i].to;
		if (v == fa) continue;
		Dfs(v, x);
		sum += f[v]; maxx = max(maxx, f[v]);
	} 
	if (!flag) return;
	int y = sum - a[x];
	f[x] = sum - y * 2;
	if (f[x] > a[x]) { flag = 0; return; }
	if (min(sum / 2, sum - maxx) < y) { flag = 0; return; }
	if (x == root && f[x] != 0) { flag = 0; return; } 
}

void Read(int &x)
{
	x = 0; int p = 0; char st = getchar();
	while (st < '0' || st > '9') p = (st == '-'), st = getchar();
	while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
	x = p ? -x : x;
	return;
}

int main()
{
	Read(n);
	for (int i = 1; i <= n; i++) Read(a[i]);
	if (n == 2){
		if (a[1] == a[2]) puts("YES");
		else puts("NO");
		return 0;
	}
	for (int i = 1, u, v; i <= n - 1; i++) Read(u), Read(v), Addedge(u, v), Addedge(v, u), in[u]++, in[v]++;
	for (int i = 1; i <= n; i++) if (in[i] > 1) { root = i; break; }
	Dfs(root, 0);
	puts(!flag ? "NO" : "YES");
	return 0;
}
原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13961220.html