Luogu5021 赛道修建

https://www.luogu.com.cn/problem/P5021

图论

十分简单的题目,想起NOIP2018时叹其为不可做题,一点一点啃暴力分(自闭)

很明显,需要二分答案,设二分到的值为\(mid\)

对于每个节点考虑,倘若有一条链经过节点\(u\)和其父亲之间的连边,那么我们只能有一条链延伸上去,在满足取得的链数最多的情况下,我们只需要让延伸上去的链最长即可,设延伸上去的最长链长为\(mxl_u\)

怎么操作?对于\(u\)的子节点\(v\),他们都存在一个\(mxl_v\),当然,\(mxl_v\)要加上\(edge_{u,v}\)之后进行操作,然后我们将这些数当成数列\(A\)

对于已经\(\ge mid\)\(a_i\),直接单独增加答案,然后去掉即可

我们从小到大匹配,对于\(a_i\),如果有\(\ge mid-a_i\)的数,直接匹配满足条件的最小的那一个,答案增加,否则\(a_i\)作为\(mxl_u\)的候选

要支持动态删除,可以直接利用\(multiset\),然后就\(AC\)

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#define N 50005
using namespace std;
int n,m,x,y,z,tot,mxl[N],fr[N],nxt[N << 1],d1[N << 1],d2[N << 1];
int l=0,r=0,mid,ans=0,kz;
multiset<int>s;
void add(int x,int y,int z)
{
    tot++;
    d1[tot]=y;
    d2[tot]=z;
    nxt[tot]=fr[x];
    fr[x]=tot;
}
void dfs(int u,int F)
{
    for (int i=fr[u];i && kz>0;i=nxt[i])
    {
        int v=d1[i];
        if (v==F)
            continue;
        if (!nxt[fr[v]])
        {
            mxl[v]=d2[i];
            continue;
        }
        dfs(v,u);
        mxl[v]+=d2[i];
    }
    if (kz<=0)
        return;
    s.clear();
    mxl[u]=0;
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d1[i];
        if (v==F)
            continue;
        if (mxl[v]>=mid)
            kz--; else
            s.insert(mxl[v]);
    }
    while (!s.empty() && kz>0)
    {
        multiset<int> :: iterator it=s.begin();
        int o=*it;
        s.erase(it);
        multiset<int> :: iterator it2=s.lower_bound(mid-o);
        if (it2!=s.end())
        {
            kz--;
            s.erase(it2);
            continue;
        }
        mxl[u]=max(mxl[u],o);
    }
}
bool check()
{
    kz=m;
    dfs(1,0);
    if (mxl[1]>=mid)
        kz--;
    return kz<=0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z),add(y,x,z);
        r+=z;
    }
    r/=m;
    while (l<=r)
    {
        mid=(l+r) >> 1;
        if (check())
        {
            ans=mid;
            l=mid+1;
        } else
            r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2020-09-10 20:43  GK0328  阅读(109)  评论(0编辑  收藏  举报