题目链接:codeforces.com/problemset/problem/349/D
题意:给一棵树,树的每个叶子节点上有权值,定义一颗树平衡:对于每一个结点u的子树都拥有相同的权值之和,问至少要减掉多少权值才能使树平衡
思路:对于每一个结点u,要知道它的总分支数r[u]及现在所拥有的权值和val[u],因为不同子树总分支数不一定相同,故结点u每次减少的值需要是其所有子树分支的最小公倍数,而且对于u的子树也需要保证平衡,故u点每次需减去的值 = lcm * 儿子个数,如果u的某个结点无法减去lcm的值,那就必须减掉整棵树的权值才能平衡
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#include <deque>
#include <ctime>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long Int;
const Int maxn = 1000100;
const Int inf = 0x3f3f3f3f;
Int gcd(Int x, Int y)
{
return y == 0 ? x : gcd(y, x % y);
}
Int lcm(Int x, Int y)
{
return x / gcd(x, y) * y;
}
Int cnt, head[maxn];
struct edge
{
Int from, to, nxt;
} e[maxn << 1];
void init()
{
cnt = 0;
memset(head, -1, sizeof(head));
}
void add(Int u, Int v)
{
e[cnt].from = u;
e[cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt++;
}
Int val[maxn], sum[maxn], r[maxn];
Int fl = 0;
void dfs(Int u, Int fa)
{
sum[u] = val[u], r[u] = 1;
Int si = 0, mi = 1e17;
for (Int i = head[u]; ~i; i = e[i].nxt)
{
Int v = e[i].to;
if (v == fa) continue;
si++;
sum[u] += sum[v];
dfs(v, u);
mi = min(mi, val[v]);
r[u] = lcm(r[u], r[v]);
if (r[u] > mi) break;
}
if (si > 0)
{
Int hh = (mi / r[u]) * r[u];
if (hh == 0)
{
fl = 1;
return ;
}
val[u] = hh * si;
r[u] = r[u] * si;
}
}
int main()
{
Int n;
while (~scanf("%I64d", &n))
{
fl = 0;
init();
Int s = 0;
for (Int i = 1; i <= n; i++)
{
scanf("%I64d", &val[i]);
s += val[i];
}
for (Int i = 1; i < n; i++)
{
Int u, v;
scanf("%I64d%I64d", &u, &v);
add(u, v);
add(v, u);
}
dfs(1, -1);
//for (Int i = 1; i <= n; i++)
//printf("%I64d %I64d\n", val[i], r[i]);
if (fl)
cout << s << endl;
else
cout << s - val[1] << endl;
}
return 0;
}