JZOJ3519.灵能矩阵 (Standard IO)

\[Description\]

Protoss 的灵能矩阵由若干个节点所构成。它们构成了一棵有根树,树根为1 号节点。定义没有子节点的节点为叶节点。叶节点内储存着一定量的能量,而非叶节点的能量为它子树中所有叶节点的能量之和。

如果一个节点的每一个子节点的能量都相同,那么这个节点就是能量平衡的。如果矩阵内每一个节点都能量平衡,则这个矩阵是能量平衡的。

被你所接管的这个灵能矩阵,似乎在长期的废弃之后已经无法保持的能量的平衡。为了重新让矩阵平衡,你可以通过将叶节点储存的能量散逸到太空中。你不可以使一个叶节点储存的能量为负数。

你希望求出最少散逸多少能量到太空中就能使灵能矩阵的能量平衡。
\[Input/Output\]

第一行包含一个整数n,表示节点的数量。

接下来一行,包含A1,A2...An 这n 个非负整数,表示每个节点自身储存的能量。保证储存能量的节点都是叶节点。

接下来n -1 行,每行包含两个数字Si, Ti,描述一条从Si 号节点到Ti 号节点的边。

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

\[Sample\]

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

\[Data\ Constraint\]

对于 \(100\)% 的数据,\(1 \leq n \leq 10^5\),\(A_i \leq 2^{30}\)

考虑到一种图,可以把正常的贪心卡掉:

5c230be8a72a4.png

我们如果让 \(8 -> 7\) 的话,那么它的儿子就会非常的尴尬。

这时我们考虑一个 \(lim_x\) 代表当这个点为 \(lim_x\) 的倍数的值时,可以让子树平衡。我们设 \(size_x\)\(x\) 的儿子的个数。

\[lim_x=size_x \times lcm \{ lim_{son} \}\]

如:

5c230da703d0c.png

\(val_{son}\) 的值就应该是:

\[val_{son} = min\{ val_{son} \}-min\{ val_{son} \} \mod lcm\{ lim_{son} \}\]

上面的算式比较显然,我要满足它可以分配成 \(lim_x\),所以就用最小的变为可以分配的(让 \(min\{ val_{son}\}\) 变为可以被 \(lcm\{ lim_{son} \}\) 整除的)。

所以 \(x\) 的值就是:

\[val_x=val_{son} \times size_x\]

不开 \(int_{64}\) 见祖宗。

时间复杂度 \(O(N \log \sqrt{N})\)

// T3

Uses math;

var
    next,reach:array[-1..810000] of longint;
    cnt,lim:array[-1..810000] of longint;
    val:array[-1..810000] of int64;
    i,j,x,y,n,tot,root:longint;
    ans:int64;

procedure add(l,r:longint);
begin inc(tot); reach[tot]:=r; next[tot]:=cnt[l]; cnt[l]:=tot;
end;

function gcd(x,y:longint):longint;
begin if x mod y<>0 then exit(gcd(y,x mod y)) else exit(y);
end;

function lcm(x,y:longint):longint;
begin exit(x*y div gcd(x,y));
end;

procedure Dfs(x,fa:longint);
var 
    minn,sum,shou:int64;
    i,size:longint;
begin
    minn:=maxlongint*843; sum:=0; size:=0;
    i:=cnt[x];
    while i<>-1 do
    begin
        if reach[i]<>fa then
        begin
            inc(sum,val[reach[i]]);
            Dfs(reach[i],x); inc(size);
            minn:=min(minn,val[reach[i]]);
            lim[x]:=lcm(lim[x],lim[reach[i]]);
        end;
        i:=next[i];
    end;
    if size=0 then exit;
    shou:=minn-minn mod lim[x];
    val[x]:=shou*size;
    lim[x]:=lim[x]*size;
    inc(ans,sum-val[x]);
end;

begin
    assign(input,'pylon.in'); reset(input);
    assign(output,'pylon.out'); rewrite(output); 
    filldword(cnt,sizeof(cnt) div 4,maxlongint*2+1);
    read(n); root:=1; ans:=0;
    for i:=1 to n do begin read(val[i]); lim[i]:=1; end;
    for i:=1 to n-1 do begin read(x,y); add(x,y); add(y,x); end;
    Dfs(root,root); writeln(ans);
    close(input); close(output);
end.

转载于:https://www.cnblogs.com/FibonacciHeap/articles/10178591.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值