https://www.luogu.com.cn/problem/P3000
最多删除k条边使得树的直径最小
二分答案,dfs的时候考虑结点u,now记录u的已经遍历的儿子的最大深度,len[j]表示j的最大深度,如果now + len[j] >= mid,把now那条边和j边 长的切断,更新now,最后在这一层,更新len[u] = now +1;
inline int rd() { char c; int x; for (; (c=getchar())<'0'||c>'9';); for (x=c-48; (c=getchar())>='0'&&c<='9';) x=x*10+c-48; return x; } const int N = 2e5 + 50; int n,k; int h[N],e[N],ne[N],idx; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int mid,cnt; int len[N]; void dfs(int u,int fa) { int now =0 ; for(int i=h[u]; ~i; i=ne[i]) { int j = e[i]; if(j == fa)continue; dfs(j,u); if(now+len[j] > mid) { cnt++; now = min(now,len[j]); } else { now = max(now,len[j]); } } len[u] = now + 1; } bool ok() { cnt=0; dfs(1,-1); return cnt <= k; } void work() { n=rd(),k=rd(); memset(h,-1,sizeof(h)); for(int i=1; i<n; i++) { int u=rd(),v=rd(); add(u,v); add(v,u); } int l=1,r=n; while(l<r) { mid = (l+r)>>1; if(ok())r=mid; else l=mid+1; } printf("%d\n",r); }