CodeForces 349D Apple Tree(树形DP)

来源:互联网 发布:自学plc编程 百度云 编辑:程序博客网 时间:2024/05/01 08:14

题目链接: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;elsecout << s - val[1] << endl;}return 0;}


1 0