zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    面向 例题
    面向
    mysql 储存过程
    php数组
    PHP 函数
    python 三大器
    python 第十一章 函数名+格式化+迭代器+递归
    python 第十章 动态参数+名称空间+嵌套+修改值
    python 第八章 r w a 等文件操作
    python 第七章 数据类型补充+遇到的坑+二次编码
  • 原文地址:https://www.cnblogs.com/Tian-Xing-Sakura/p/13961220.html
Copyright © 2011-2022 走看看