AtCoder Grand Contest 010 --C:Cleaning

Cleaning

时间限制: 2 Sec 内存限制: 256 MB

题目描述

There is a tree with N vertices, numbered 1 through N. The i-th of the N−1 edges connects vertices ai and bi.

Currently, there are Ai stones placed on vertex i. Determine whether it is possible to remove all the stones from the vertices by repeatedly performing the following operation:

Select a pair of different leaves. Then, remove exactly one stone from every vertex on the path between those two vertices. Here, a leaf is a vertex of the tree whose degree is 1, and the selected leaves themselves are also considered as vertices on the path connecting them.
Note that the operation cannot be performed if there is a vertex with no stone on the path.

Constraints
2≤N≤105
1≤ai,bi≤N
0≤Ai≤109
The given graph is a tree.

输入

The input is given from Standard Input in the following format:

N
A1 A2 … AN
a1 b1
:
aN−1 bN−1

输出

If it is possible to remove all the stones from the vertices, print YES. Otherwise, print NO.

样例输入

5
1 2 1 1 2
2 4
5 2
3 2
1 3

样例输出

YES

提示
All the stones can be removed, as follows:

Select vertices 4 and 5. Then, there is one stone remaining on each vertex except 4.
Select vertices 1 and 5. Then, there is no stone on any vertex.

分析

对于每颗子树,该子树的根上的石头有两种消去方式:

  • 选择两个子树内部的叶子
  • 选择一个子树中的叶子和子树外部的叶子

我们假设通过第一种方式消去的根的石头数为\(p\),那么第二种方式消去数应为 \(A[root]-p\)。根消去\(p\)时,这个根的儿子应当总共消去\(2p\),消去后应满足式子$$sum-2p=A[root]-p$$所以\(p=sum-A[root]\),这样操作一次之后就可以把子树等价为还有\(A[root]-p\)个石头的叶子。

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <vector>
#include <map>
using namespace std;
const int maxn=200050;
typedef long long ll;
struct Edge
{
    int v,nxt;
}e[maxn*2];
int h[maxn],tot;
void addEdge(int x,int y){
    e[++tot]=(Edge){y,h[x]};
    h[x]=tot;
}
 
ll w[maxn];
bool ans=true;
ll dfs(int x,int x_fa){
    ll sum=0,cnt=0,M=0;
    for (int i = h[x]; i ; i=e[i].nxt)
    {
        if(e[i].v!=x_fa){
            ll t=dfs(e[i].v,x);
            sum+=t;
            M=max(M,t);
            cnt++;
        }
    }
    if(cnt==0) return w[x];
    if(cnt==1){
        if(sum!=w[x]) ans=false;
        return sum;
    }
    ll p=sum-w[x];
    if(p<0||w[x]<p||sum-M<p) ans=false;
    return w[x]-p;
}
int deg[maxn];
int main(int argc, char const *argv[])
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
    {
        scanf("%lld", w+i);
    }
    for (int i = 0; i < n-1; ++i)
    {
        int x,y;
        scanf("%d%d", &x,&y);
        addEdge(x,y);
        addEdge(y,x);
        deg[x]++;
        deg[y]++;
    }
    if(n==1){
        printf("%s\n", w[1]?"NO":"YES");
        return 0;
    }
    if(n==2){
        printf("%s\n", w[1]==w[2]?"YES":"NO");
        return 0;
    }
    int root=1;
    for (int i = 1; i <= n; ++i)
    {
        if(deg[i]>1) root=i;
    }
    if(dfs(root,root)!=0) ans=false;
    if(ans) printf("YES\n");
    else printf("NO\n");
    return 0;
}
posted @ 2018-04-21 12:25  sciorz  阅读(128)  评论(0编辑  收藏  举报