https://ac.nowcoder.com/acm/contest/6037/F
很诡异,对于8 3 2 1 1这种,答案是7(3+2+1+1), 对于6 5 4 3 2 1这种,是(6+5+4+3+2+1)/2
所以求出每种颜色的最大数量 还有颜色总数就能在O(1)算出来一棵树了。但是吧。。。真想不到
具体看代码吧,有dus on tree板子
#include<cstdio> #include<iostream> #include<algorithm> #include<set> #include<vector> using namespace std; const int maxn = 2e5 + 100; typedef long long ll; vector<int>G[maxn]; void add(int be, int en) { G[be].push_back(en); } int siz[maxn]; int son[maxn]; ll sum[maxn]; ll ans[maxn]; ll b[maxn]; ll cnt[maxn]; ll list[maxn]; ll maxx = 0; int dfs(int x, int fa) { siz[x] = 1; sum[x] = b[x]; int c = 0; for (int p : G[x]) { if (p == fa) continue; dfs(p, x); siz[x] += siz[p]; sum[x] += sum[p]; if (siz[p] > c) { c = siz[p]; son[x] = p; } } return 0; } int cal(int x, int fa, int f) { cnt[list[x]] += b[x]; maxx = max(maxx, cnt[list[x]]); for (int p : G[x]) { if (p == fa || p == f) continue; cal(p, x, f); } return 0; } int cal2(int x, int fa, int f) { cnt[list[x]] -= b[x]; for (int p : G[x]) { if (p == fa ) continue; cal2(p, x, f); } return 0; } int dfs2(int x, int fa, int flag) { for (int p : G[x]) { if (p == fa) continue; if (p == son[x]) continue; dfs2(p, x, 0);//把轻儿子算一遍 } if (son[x] != 0) { dfs2(son[x], x, 1);//最后算重儿子 } cal(x, fa, son[x]);//重儿子算过了,不必重算 if (maxx <= sum[x] / 2) { ans[x] = sum[x] / 2; } else { ans[x] = sum[x] - maxx; } if (flag == 0) {//清空 maxx = 0; cal2(x, fa, son[x]); } return 0; } int main() { int n; int be; scanf("%d", &n); int x, y; for (int i = 2; i <= n; i++) { scanf("%d %d", &x, &y); add(x, y); add(y, x); } for (int i = 1; i <= n; i++) { scanf("%lld %lld", &list[i], &b[i]); } dfs(1, -1); dfs2(1, -1, 0); for (int i = 1; i <= n; i++) { printf("%lld ", ans[i]); } return 0; }