本质就是贪心,考试的时候太急了,有一些小错误没找出来,丢了50分。
首先二分答案,判断该长度下最多有几条路。
假设二分的这个答案为k。
dp[]表示以该节点为根的子树中最多有几条路。
more[]表示在保证子树中答案最优的情况下,一端为该节点,一端在子树中节点的最长的链。
很明显,对于一个节点,就有子节点个数条路径长度,如果这个值大于k,则dp[u]++,否则存入b[]中
对b排序,从小到大扫,对每一个没有取过的值,二分出能满足条件的没有取过的最小的值,dp[u]++。
最后more[u]=b[]中没有取过的最大的值
其实是一道水题,还是代码功底不够,没调出来。
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
int n,m,head[N*2],dp[N],b[N],more[N],vis[N],tot;
int read()
{
int x=0,f=1;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
return x*f;
}
struct node
{
int vet,nxt,len;
}edge[N*2];
void add(int u,int v,int w)
{
edge[++tot].vet=v;
edge[tot].nxt=head[u];
head[u]=tot;
edge[tot].len=w;
}
int cmp(int x,int y)
{
return x<y;
}
void dfs(int u,int fa,int k)
{
int cnt=0;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].vet;
if(v!=fa)
{
dfs(v,u,k);
dp[u]+=dp[v];
}
}
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].vet;
if(v!=fa)
{
if(more[v]+edge[i].len>=k)dp[u]++;else
b[++cnt]=more[v]+edge[i].len;
}
}
for(int i=1;i<=cnt;i++)vis[i]=0;
sort(b+1,b+cnt+1,cmp);
for(int i=1;i<=cnt;i++)
if(!vis[i])
{
int L=i+1,R=cnt;
while(L<R)
{
int Mid=(L+R)>>1;
if(b[Mid]+b[i]>=k)R=Mid;else L=Mid+1;
}
while(L<=cnt&&vis[L])L++;
if(L>cnt)continue;
if(b[L]+b[i]>=k&&!vis[L])
{
dp[u]++;vis[L]=1;vis[i]=1;
}else continue;
}
for(int i=cnt;i>=1;i--)
if(!vis[i])
{
more[u]=b[i];
break;
}
}
int check(int k)
{
for(int i=1;i<=n;i++)
{
dp[i]=0;more[i]=0;
}
dfs(1,0,k);
if(dp[1]>=m)return 1;else return 0;
}
int main()
{
n=read(),m=read();
int sum=0;
for(int i=1;i<n;i++)
{
int u=read(),v=read(),w=read();
sum+=w;
add(u,v,w);add(v,u,w);
}
int l=1,r=sum;
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid))l=mid;else r=mid-1;
}
printf("%d\n",l);
return 0;
}