P3554 [POI2013]LUK-Triumphal arch

\(\color{#0066ff}{ 题目描述 }\)

给一颗树,1号节点已经被染黑,其余是白的,两个人轮流操作,一开始B在1号节点,A选择k个点染黑,然后B走一步,如果B能走到A没染的节点则B胜,否则当A染完全部的点时,A胜。求能让A获胜的最小的k

\(\color{#0066ff}{输入格式}\)

第一行:n

然后是n-1条边

\(\color{#0066ff}{输出格式}\)

最小的k

\(\color{#0066ff}{输入样例}\)

7
1 2
1 3
2 5
2 6
7 2
4 1

\(\color{#0066ff}{输出样例}\)

3

\(\color{#0066ff}{数据范围与提示}\)

\(1\leq n \leq 300000\)

\(\color{#0066ff}{ 题解 }\)

考虑当前B在一个点上,首先,他肯定不会走回头路,因为来的路一定都被染黑了,肯定不优的

如果当前点的子树个数>k,那么显然A是不能全染黑的,B就有机可乘了qwq

如果子树个数不足,那么显然剩下的一些染色机会就会被分配到子树中去

我们设f[i]表示将i的子树全部染黑(不包括i)还需要几次

\(f[u] = \sum{(f[v]+1)} - k\)

二分ans,我们只需判\(f[1]\)是否为0即可

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
struct node {
	int to;
	node *nxt;
	node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
	void *operator new (size_t) {
		static node *S = NULL, *T = NULL;
		return (S == T) && (T = (S = new node[1024]) + 1024), S++;
	}
};
const int maxn = 3e5 + 100;
int f[maxn];
node *head[maxn];
int n;
void add(int from, int to) {
	head[from] = new node(to, head[from]);
}
void dfs(int x, int fa, int mid) {
	f[x] = 0;
	for(node *i = head[x]; i; i = i->nxt) {
		if(i->to == fa) continue;
		dfs(i->to, x, mid);
		f[x] += (f[i->to] + 1);
	}
	f[x] = std::max(0, f[x] - mid);
}
bool ok(int mid) {
	dfs(1, 0, mid);
	return f[1] == 0;
}
int main() {
	n = in();
	int x, y;
	for(int i = 1; i < n; i++) {
		x = in(), y = in();
		add(x, y), add(y, x);
	}
	int l = 0, r = n, ans = n;
	while(l <= r) {
		int mid = (l + r) >> 1;
		if(ok(mid)) ans = mid, r = mid - 1;
		else l = mid + 1;
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2019-01-08 11:18  olinr  阅读(208)  评论(0编辑  收藏  举报