【NOIP2013模拟11.6A组】灵能矩阵(pylon)

Description

Protoss 的灵能矩阵由若干个节点所构成。它们构成了一棵有根树,树根为1 号节点。定义没有子节点的节点为叶节点。叶节点内储存着一定量的能量,而非叶节点的能量为它子树中所有叶节点的能量之和。
如果一个节点的每一个子节点的能量都相同,那么这个节点就是能量平衡的。如果矩阵内每一个节点都能量平衡,则这个矩阵是能量平衡的。
被你所接管的这个灵能矩阵,似乎在长期的废弃之后已经无法保持的能量的平衡。为了重新让矩阵平衡,你可以通过将叶节点储存的能量散逸到太空中。你不可以使一个叶节点储存的能量为负数。
你希望求出最少散逸多少能量到太空中就能使灵能矩阵的能量平衡。

Input

第一行包含一个整数n,表示节点的数量。
接下来一行,包含A1,A2…An 这n 个非负整数,表示每个节点自身储存的能量。保证储存能量的节点都是叶节点。
接下来n -1 行,每行包含两个数字Si, Ti,描述一条从Si 号节点到Ti 号节点的边。

Output

第一行包含一个整数,表示最少要散逸多少单位的能量才能使灵能矩阵的能量平衡。

Sample Input

6
0 0 12 13 5 6
1 2
1 3
1 4
2 5
2 6

Sample Output

6

Data Constraint

对于15% 的数据,1<= n <= 10。
对于30% 的数据,对于边Si, Ti,Si + 1 ̸= Ti 的边数不超过3 条。
对于50% 的数据,1<= n <= 1000。
对于100% 的数据,1 <= n <= 100000,1 <= Ai <= 2^30。

小结

我们看一下样例的图
这里写图片描述
这样看很像一道贪心,但是我们看另一个图:
这里写图片描述
按平常做法,我们应该把8减去一然后答案就是一,但是我们发现,减去一后的8是无法分成两份的,于是我们就要维护一个g[x]表示假如把x这个点改成m,那m应该是g[x]的倍数。
那么这个g[x]应该怎么求呢,应该是(所有g[son]的lcm)*(son的个数),想想为什么,因为我们要是我们这个被分下去的数要满足是自己son数的个数,还要满足是自己son的son的个数……这样下去,就是lcm咯~
于是我们就可以做了,每次我们设把这一排子节点改成m,然后m就应该是=min(son中最小的一个)-min mod ( g[x]son ),为什么呢,因为我们要满足它只能减,不能加,所以要取最小的,然后又要是g[x]的倍数,所以就要减去它们的余数,就可以整除了,最优一次次累加,就得到了ans~~

var
        n,m,i,j,x,y,tot:longint;
        ans:int64;
        a,g:array[0..100000]of int64;
        tov,last,next:array[0..200000]of longint;
        bz:array[0..100000]of boolean;
procedure insert(x,y:longint);
begin
        inc(tot);
        tov[tot]:=y;
        next[tot]:=last[x];
        last[x]:=tot;
end;
function gcd(a,b:longint):longint;
begin
        if a mod b<>0 then exit(gcd(b,a mod b))
        else exit(b);
end;
function lcm(x,y:longint):longint;
begin
        exit(x*y div gcd(x,y));
end;
procedure dg(t:longint);
var
        i,y,mi,sum,num,g1,m:int64;
begin
        bz[t]:=true;
        sum:=0;
        mi:=1 shl 62;
        i:=last[t];
        num:=0;
        g1:=1;
        while i<>0 do
        begin
                y:=tov[i];
                if bz[y]=false then
                begin
                        dg(y);
                        g1:=lcm(g1,g[y]);
                        if mi>a[y] then mi:=a[y];
                        sum:=sum+a[y];
                        inc(num);
                end;
                i:=next[i];
        end;
        g[t]:=g1*num;
        if num=0 then g[t]:=1;
        if num>0 then
        begin
                m:=mi-mi mod (g[t] div num);
                ans:=ans+sum-m*num;
                a[t]:=m*num;
        end;
end;
begin
        assign(input,'pylon.in');reset(input);
        assign(output,'pylon.out');rewrite(output);
        readln(n);
        for i:=1 to n do
                read(a[i]);
        for i:=1 to n-1 do
        begin
                readln(x,y);
                insert(x,y);
        end;
        dg(1);
        writeln(ans);
        close(input);
        close(output);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值