1 2 3 4

Dus on tree 月出皎兮,佼人僚兮。

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\n", ans[i]);
	}
	return 0;
}

  

posted @ 2020-08-20 17:30  Lesning  阅读(149)  评论(0)    收藏  举报