【JZOJ 5028】跳蚤王国

Description

跳蚤王国爆发了一场动乱,国王在镇压动乱的同时,需要在跳蚤国地方钦定一个人来做宰相。
然而当时国王的钦定方式很奇怪,跳蚤王国可以看成一棵树,国王认为宰相必须更好地位跳蚤服务,所以他会选择一个到所有节点距离和最小的节点,并在这个节点中钦定,如果有多个节点满足距离和最小则任选一个。
然而跳蚤国的动乱实在是太厉害了,以至于树的心态可能也会发生改变也就是说,树上可能会有若干条边消失,如果这个情况出现的话一定会有同样数目的边出现,以保证整个结构仍然是一棵树。
现在这个跳蚤想知道每个节点中的跳蚤如果要被钦定,至少需要多少条边消失(当然也有同样数目的边出现)。作为这只跳蚤的一名真正的粉丝,你能帮他解决这个问题吗?

Input

第一行一个正整数n表示树中的点数。
接下来n-1行,每行两个正整数u,v,表示点u与点v之间有一条树边。

Output
输出n行,第i行一个数,表示第i个节点如果要被钦定至少需要多少条消失。

Sample Input

10
1 2
1 3
1 4
1 5
1 6
1 7
1 8
1 9
1 10

Sample Output

0
4
4
4
4
4
4
4
4
4

Data Constraint

思路

先找出重心,然后我们求出重心需要删掉多少个孩子才能让剩下的大小不超过整棵树的一半。
可以发现那么其他点的答案要么是这个值减一,要么就是这个值,判断也不难。

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 77;

int ls[N], current, n, siz[N], root, answer[N], acc, limit_id;
vector<int> vec;

struct E
{
	int to, nxt;
} e[N << 1];

bool compare(int a, int b) { return siz[a] > siz[b]; }

void addpath(int src, int dst)
{
	e[current].to = dst, e[current].nxt = ls[src];
	ls[src] = current++;
}

void dfs(int u, int fa)
{
	int max_son = 0;
	siz[u] = 1;
	for (int i = ls[u]; i != -1; i = e[i].nxt)
		if (e[i].to != fa)
			dfs(e[i].to, u), siz[u] += siz[e[i].to], max_son = max(max_son, siz[e[i].to]);
	max_son = max(max_son, n - siz[u]);
	if (max_son <= (n >> 1))
		root = u;
}

void getAns(int u, int fa)
{
	answer[u] = limit_id - (siz[u] + acc >= (n >> 1)) + 1;
	for (int i = ls[u]; i != -1; i = e[i].nxt)
		if (e[i].to != fa)
			getAns(e[i].to, u);
}

int main()
{
	freopen("flea.in", "r", stdin);
	freopen("flea.out", "w", stdout);
	memset(ls, -1, sizeof(ls));
	scanf("%d", &n);
	for (int i = 1, u, v; i <= n - 1; i++)
		scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
	dfs(1, 0), dfs(root, 0);
	for (int i = ls[root]; i != -1; i = e[i].nxt)
		vec.push_back(e[i].to);
	sort(vec.begin(), vec.end(), compare);
	limit_id = -1;
	for (int i = 0, siz_ = vec.size(); i < siz_; i++)
	{
		acc += siz[vec[i]];
		if (acc >= (n >> 1))
		{
			limit_id = i;
			break;
		}
	}
	for (int i = 0; i <= limit_id; i++)
		acc -= siz[vec[i]], getAns(vec[i], root), acc += siz[vec[i]];
	if (limit_id != -1)
		acc -= siz[vec[limit_id]];
	for (int i = limit_id + 1, siz_ = vec.size(); i < siz_; i++)
		getAns(vec[i], root);
	for (int i = 1; i <= n; i++)
		printf("%d\n", answer[i]);
	return 0;
}
发布了703 篇原创文章 · 获赞 392 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/104086295