题目大意:给定一棵树,可以删掉k条边,求删掉后森林中所有树直径的最大值的最小值
最大值最小,典型的二分答案
此题我们二分树的直径,每次二分DFS一次,对于每个节点统计出所有子树删边后的dis,排序,贪心删掉最大的,直到最大的两个子树相加不会超过二分的答案为止
时间复杂度O(nlog^2n)
老子的二分居然写挂了。。。桑不起啊啊啊啊
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
struct abcd{
int to,next;
}table[M<<1];
int head[M],tot;
int n,m,ans;
int fa[M],dis[M],stack[M],top;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void Tree_DP(int x,int limit)
{
int i,bottom=top;
for(i=head[x];i;i=table[i].next)
{
if(table[i].to==fa[x])
continue;
fa[table[i].to]=x;
Tree_DP(table[i].to,limit);
stack[++top]=dis[table[i].to]+1;
}
sort(stack+bottom+1,stack+top+1);
for(i=top;i>bottom;i--)
if(stack[i]>limit||i>bottom+1&&stack[i]+stack[i-1]>limit)
++ans;
else
break;
dis[x]=i==bottom?0:stack[i];
top=bottom;
}
int Bisection()
{
int l=1,r=n;
while(l+1<r)
{
int mid=l+r>>1;
ans=0;Tree_DP(1,mid);
if(ans>m)
l=mid;
else
r=mid;
}
ans=0;Tree_DP(1,l);
if(ans<=m)
return l;
return r;
}
int main()
{
int i,x,y;
cin>>n>>m;
for(i=1;i<n;i++)
scanf("%d%d",&x,&y),Add(x,y),Add(y,x);
printf("%d\n", Bisection() );
}