.https://atcoder.jp/contests/arc116/tasks/arc116_e
学习自https://blog.csdn.net/RealKing_sblog/article/details/115359363
这题一眼就是二分答案转判定,然而不知道怎么得到最少的关键点数
g[u]表示从u开始到最远的没被已有的树占领的点的距离,f[u]表示已有的树跟到u的最小距离。
如果f[u]+g[u]<=mid,那么说明u这整棵子树都被下面的树的根给覆盖掉了,直接g[u]=-inf,因为不存在还没被覆盖的u了
否则如果g[u]=mid,则说明当前必须要放一个根在这里了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
const int inf=1e9+10;
int n,m,k,cnt,tot,cas,ans;
int a[maxl],f[maxl],g[maxl];
bool vis[maxl];
char s[maxl];
vector<int> e[maxl];
inline void prework()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n-1;i++)
{
int u,v;scanf("%d%d",&u,&v);
e[u].push_back(v);
e[v].push_back(u);
}
}
inline void dfs(int u,int fa,int mid)
{
f[u]=inf;g[u]=0;
for(int v:e[u])
if(v!=fa)
{
dfs(v,u,mid);
f[u]=min(f[u],f[v]+1);
g[u]=max(g[u],g[v]+1);
}
if(f[u]+g[u]<=mid)
g[u]=-inf;
else if(g[u]==mid)
g[u]=-inf,f[u]=0,++cnt;
}
inline bool jug(int mid)
{
cnt=0;
dfs(1,0,mid);
if(g[1]>=0) cnt++;
return cnt<=k;
}
inline void mainwork()
{
int l=0,r=n;
while(l+1<r)
{
int mid=(l+r)>>1;
if(jug(mid))
r=mid;
else
l=mid;
}
if(jug(l)) ans=l;
else ans=r;
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}