1
老大
先以图为例
这题二分,当二分出来一个 \(dis\) 后,考虑怎么选取最优。首先找到最深的点上面 \(dis\) 个位置(这样可以满足到那个点子树内的距离满足的基础上到外面的距离最小),比如 \(dis=1\),那么应选择 \(6\) 的 \(1\) 级祖先 \(3\),然后再以这个点为根搜(以 \(3\) 为根最深的是 \(5\)),然后从 \(5\) 往上 \(1\) 级是 \(2\),然后发现以 \(3,2\) 为基准时 \(8\) 不行,所以失败。
#include<bits/stdc++.h>
using namespace std;
const int N=200010,M=2*N;
int n,e[M],ne[M],h[N],idx,dep[N],st,up[N],f[N],mid;
bool vis[N];
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int x,int fa){
dep[x]=dep[fa]+1;
f[x]=fa;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(j==fa)continue;
dfs(j,x);
}
}
void tag(int &x){
dfs(x,0);
for(int i=1;i<=n;++i)
if(dep[i]<=mid)vis[i]=1;
}
bool check(){
memset(vis+1,0,n);
int x=up[mid];
tag(x);
int y=max_element(dep+1,dep+1+n)-dep;
int cnt=mid;
while(cnt&&y!=x)--cnt,y=f[y];
tag(y);
return accumulate(vis+1,vis+1+n,0)==n;
}
int main(){
dep[0]=-1;
memset(h,-1,sizeof h);
scanf("%d",&n);
for(int i=1;i<n;++i){
int a,b;
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs(1,0);
st=max_element(dep+1,dep+1+n)-dep;
up[0]=st;
for(int i=1;i<=n;++i){
up[i]=f[up[i-1]];
if(!up[i])up[i]=1;
}
int l=1,r=n;
while(l<r){
mid=l+r>>1;
if(check())r=mid;
else l=mid+1;
}
printf("%d",r);
return 0;
}