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;
}