(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}{数据范围与提示})
(1leq 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
", ans);
return 0;
}