【luoguP3000】 [USACO10DEC]牛的健美操Cow Calisthenics
二分答案,判断需要断几条边,用\(f[i]\)表示以\(i\)为根的子树断边后的最长路径,对于一个点\(u\),存在\(f[v]>mid\)时就删到\(v\)的边\(f[v1]+f[v2]>mid\)时就删\(f\)较大的边,可以sort之后搞一搞
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int MAXN=100010;
inline int read(){
int x=0; char c=getchar();
while(c<'0') c=getchar();
while(c>='0') x=x*10+c-'0',c=getchar();
return x;
}
int n,k;
int Head[MAXN],num;
struct NODE{
int to,nxt;
}e[MAXN<<1];
inline void add(int x,int y){
e[++num].to=y;
e[num].nxt=Head[x];
Head[x]=num;
}
int f[MAXN],Cnt,mid;
inline bool cmp(int x,int y){
return x>y;
}
void dfs(int x,int fa){
vector<int> t; t.clear();
for(int i=Head[x];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa) continue;
dfs(v,x);
t.push_back(f[v]+1);
}
if(!t.size()) return;
sort(t.begin(),t.end(),cmp);
int l=t.size(),i=0;
for(;i<l;++i)
if(t[i]>mid) ++Cnt;
else break;
for(;i+1<l;++i)
if(t[i]+t[i+1]>mid) ++Cnt;
else break;
f[x]=i<l?t[i]:0;
}
inline bool check(){
memset(f,0,sizeof(f));
Cnt=0;
dfs(1,0);
return Cnt<=k;
}
int main()
{
scanf("%d%d",&n,&k);
int x,y;
for(int i=1;i<n;++i){
x=read(); y=read();
add(x,y); add(y,x);
}
int l=1,r=n;
while(l<r){
mid=(l+r)>>1;
if(check()) r=mid;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}