前言
这道题是一个树上二分的题,其实很有思维量的
思路
首先这是一道让选择m个节点,每一个点到关键节点的距离的最小值中的最大值最小化的一道题目
首先第一个最小值就是每一个选定节点到最近的关键节点的距离,其实不用太在意,之后就是最大值最小化,这显然是二分答案的一道题,所以考虑二分一个mid,看看可不可以用mid的距离去覆盖全部的关键节点,之后就是考虑这个check
check
首先我们可以用覆盖的思想去理解这道题,就是每一个选定节点可以覆盖全部的关键节点就是一个true,那么我们就用两个数组
f[x] --> 表示以x为root的子树中距离最大的没有覆盖的关键节点的dis
g[x] – > 表示以x为root的子树中距离最近的选定节点的距离
那么转移就是 f[x]=max(f[x],f[y]+1) g[x]=min(g[x],g[y]+1)
这个比较显然,注意最开始f[x]=-inf g[x]=inf
那么之后就是考虑对于节点的选定
假如 1.f[x]+g[x]<=mid 也就说明这个子树的全部关键节点都可以被覆盖
2. g[x]>mid && b[x] == 1 也就是说明这个点是关键节点,并且没人可以管,所以就交给父亲处理 所以f[x]=max(f[x],0)
3. f[x] = mid 也就是说明这个子树内有一个关键节点没有办法被任何人覆盖,只有这个点,所以tot++
最后就是二分了
注意
二分的左边界可以为0,因为我可以距离为0
还有就是dfs结束后我们要特判一下根的f,假如有节点没有被覆盖,那么就要tot++,也就是把根给加上
code
#include<bits/stdc++.h>
using namespace std;
#define max(a,b) ((a)>(b)? a : b)
#define min(a,b) ((a)>(b)? b : a)
#define ll long long
const int maxn=300005;
const ll inf=1e9;
int n,m