NOIP2018Day1T3——赛道修建


本质就是贪心,考试的时候太急了,有一些小错误没找出来,丢了50分。
首先二分答案,判断该长度下最多有几条路。
假设二分的这个答案为k。
dp[]表示以该节点为根的子树中最多有几条路。
more[]表示在保证子树中答案最优的情况下,一端为该节点,一端在子树中节点的最长的链。
很明显,对于一个节点,就有子节点个数条路径长度,如果这个值大于k,则dp[u]++,否则存入b[]中
对b排序,从小到大扫,对每一个没有取过的值,二分出能满足条件的没有取过的最小的值,dp[u]++。
最后more[u]=b[]中没有取过的最大的值
其实是一道水题,还是代码功底不够,没调出来。
C o d e Code:

#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;
}
发布了232 篇原创文章 · 获赞 463 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_34531807/article/details/87738825