【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
",l);
	return 0;
}
原文地址:https://www.cnblogs.com/yjkhhh/p/11743692.html