题目:
题解:
奶牛题全是权限题?
最大值最小——二分嘛
还是要好好理解树的直径这道题目。。。然后灵活变通,这样你就可以知道这道题的方法
把找树的直径的过程“放慢拉长”,贪心的从子树开始截取已经要长出去的片段
长出去的片段一定要截取最大的啊(贪心一点嘛,小的更有发展空间啊
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define N 100005
using namespace std;
int tot,nxt[N*2],point[N],v[N*2],cnt,f[N],a[N];//f[x]表示x点到子树的最长链的距离
int cmp(int a,int b){return a>b;}
void addline(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int fa,int limit)
{
f[x]=0;//每次都memset不觉得太慢了嘛
bool fff=false;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
dfs(v[i],x,limit);
fff=true;
f[x]=max(f[x],f[v[i]]+1);
}
if (!fff) return;//f[x]的完善完成
a[0]=0;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa) a[++a[0]]=f[v[i]]+1;//每条链长
sort(a+1,a+a[0]+1,cmp);
for (int i=1;i<a[0];i++)
if (a[i]+a[i+1]>limit) a[i]=0,cnt++;
//从最大的开始,如果a[1]被t了,最大的组合就是a[2]+a[3],再考虑t不t a[2];如果a[1]没被t,啊呀最大的组合a[1]+a[2]都没事你们后面的肯定没事啊
if (a[a[0]]>limit) a[a[0]]=0,cnt++;
sort(a+1,a+a[0]+1,cmp);//很多都断开了(a[i]=0),要重排
f[x]=a[1];
}
int check(int limit)
{
cnt=0;
dfs(1,0,limit);
return cnt;
}
int main()
{
int n,s,i;
scanf("%d%d",&n,&s);
for (i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addline(x,y);
}
int l=1,r=n-1;
while (l<=r)//直径的长度
{
int mid=(l+r)>>1;
if (check(mid)<=s) r=mid-1;
else l=mid+1;
}
printf("%d",r+1);
}