B. Apple Tree----dfs

来源:互联网 发布:手机脚本怎么编程 编辑:程序博客网 时间:2024/05/16 10:00

B. Apple Tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

You are given a rooted tree with n vertices. In each leaf vertex there's a single integer — the number of apples in this vertex.

The weight of a subtree is the sum of all numbers in this subtree leaves. For instance, the weight of a subtree that corresponds to some leaf is the number written in the leaf.

A tree is balanced if for every vertex v of the tree all its subtrees, corresponding to the children of vertex v, are of equal weight.

Count the minimum number of apples that you need to remove from the tree (specifically, from some of its leaves) in order to make the tree balanced. Notice that you can always achieve the goal by just removing all apples.

Input

The first line contains integer n (2 ≤ n ≤ 105), showing the number of vertices in the tree. The next line contains n integers a1, a2, ..., an(0 ≤ ai ≤ 108)ai is the number of apples in the vertex number i. The number of apples in non-leaf vertices is guaranteed to be zero.

Then follow n - 1 lines, describing the tree edges. Each line contains a pair of integers xi, yi (1 ≤ xi, yi ≤ n, xi ≠ yi) — the vertices connected by an edge.

The vertices are indexed from 1 to n. Vertex 1 is the root.

Output

Print a single integer — the minimum number of apples to remove in order to make the tree balanced.

Please, do not write the %lld specifier to read or write 64-bit integers in С++. It is preferred to use the sin, cout streams cincout or the %I64d specifier.

Examples
input
60 0 12 13 5 61 21 31 42 52 6
output
6

题目链接:http://codeforces.com/contest/348/problem/B


题目的意思是说有一个有根树,现在每一个点有一个权值(苹果数),非叶节点的权值(苹果数)保证是0,现在我们要构造一棵平衡树,平衡的条件是该节点的所有儿子节点的权值和要相同,问最少删除多少个苹果使树平衡。


四个多小时终于把这棵树征服。。。

我上来先想树形dp,想了近一个小时发现好像不是树形dp。。。现在我们考虑题目的条件,可以转化为树的每一层的苹果数都相同(除叶子节点),所以我们只需要按照每一层的最少的那个苹果数把其他的删掉就可以了,所以我想到了dfs,然后去实现,然后就没有然后了,没有实现出来。。。无奈之下去搜了博客,发现大佬也是dfs做的,但是思路完全不同。

大牛链接:http://blog.csdn.net/harlow_cheng/article/details/73527548

学习到了,受教。

然后想到了某一只匿名打码(QAQ)的话,自己反思了这个题为什么不能用树形dp去做。

树形dp也是递归维护,但一般是从儿子维护到父亲,这个题我们并不用从儿子推到父亲,而是直接去计算父亲需要多少个苹果即可(为什么想到了背包中的泛化物品...)。

代码:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#define LL long long#define inf 0x3f3f3f3f3f3f3f3fusing namespace std;const int MAXN=500105;LL a[MAXN];LL d[MAXN];LL s[MAXN];LL sum=0;LL ans;vector<int>vec[MAXN];bool flag=true;LL LCM(LL x,LL y){    return x/__gcd(x,y)*y;}void dfs1(int x,int fa){    if(!flag)        return ;    d[x]=1,s[x]=a[x];    if(vec[x].size()==1&&x!=1){//叶子节点        return ;    }    int len=vec[x].size();    d[x]=1;    for(int i=0;i<len;i++){        int y=vec[x][i];        if(y==fa)            continue;        dfs1(y,x);        d[x]=LCM(d[x],d[y]);        if(d[x]>sum){//需要全部删掉,这棵树权值都为0也满足题目条件            flag=false;            return ;        }        s[x]+=s[y];    }    if(x==1){        d[x]*=len;//根    }    else{        d[x]*=(len-1);//非根    }}void dfs2(LL x,LL fa){    LL len=vec[x].size();    if(len==1&&x!=1){        return ;    }    LL mix=inf,cnt=0;    for(int i=0;i<len;i++){        LL y=vec[x][i];        if(y==fa)            continue;        dfs2(y,x);        mix=min(mix,s[y]);        cnt+=s[y];    }    LL t;    if(x==1){        t=d[x]/len;    }    else{        t=d[x]/(len-1);    }    t=(mix/t)*t;    if(x==1){        ans+=cnt-t*len;    }    else{        ans+=cnt-t*(len-1);    }    s[x]=a[x];    for(int i=0;i<len;i++){        LL y=vec[x][i];        if(y==fa)            continue;        s[y]=t;        s[x]+=s[y];    }}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++){        scanf("%I64d",&a[i]);        sum+=a[i];    }    for(int i=0;i<n-1;i++){        LL x,y;        scanf("%I64d%I64d",&x,&y);        vec[x].push_back(y);        vec[y].push_back(x);    }    dfs1(1,-1);    if(!flag){        printf("%I64d\n",sum);        return 0;    }    dfs2(1,-1);    printf("%I64d\n",ans);    return 0;}