zoukankan      html  css  js  c++  java
  • 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
    ", w[1]?"NO":"YES");
            return 0;
        }
        if(n==2){
            printf("%s
    ", 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
    ");
        else printf("NO
    ");
        return 0;
    }
    
  • 相关阅读:
    线程+IO流
    jiava trim()
    statement 的延伸 ----》PreparedStatement
    java中math的用法
    java中获取所有文件--(递归调用)
    编写一个JAVA类,用于计算两个日期之间的周数。
    java中数组排序.知识点
    javascript 常用功能总结
    jquery
    创建 HTML内容
  • 原文地址:https://www.cnblogs.com/sciorz/p/8900563.html
Copyright © 2011-2022 走看看