P5021 赛道修建

题面请见(https://www.luogu.org/problemnew/show/P5021)
其实考场上想出来正解了qaq,无非是一个贪心的dp,可是考场上没来得及写完,就打了几个部分分,懒得手写lower_bound了,借鉴dalao胡搞了一个multiset

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define N 50005
#define IT multiset<int>::iterator 
using namespace std;
int n,m;
struct Edge
{
    int to,dis;
};
int tot;
vector<Edge>from[N];
multiset<int>rest[N];
void add(int a,int b,int c)
{
    from[a].push_back((Edge){b,c});
} 
int dp(int u,int fa,int x)
{
    rest[u].clear();
    for(int i=0;i<from[u].size();i++){
        int v=from[u][i].to;
        int d=from[u][i].dis;
        if(v==fa) continue;
        int l=dp(v,u,x)+d;
        if(l>=x) tot++;
        else rest[u].insert(l);
    }
    for(IT it=rest[u].begin();it!=rest[u].end();){
        IT find=rest[u].lower_bound(x-*(it));
        if(find!=rest[u].end())
        {//能找到
            if(find==it)
            {
                find++;
                if(find==rest[u].end())
                {
                    it++;
                    continue;
                }
            }
            tot++;
            rest[u].erase(find);
            rest[u].erase(it++);
        }
        else it++;
    } 
    if(!rest[u].empty())
    {
        IT final=rest[u].end();
        final--;
        return *final;
    }
    return 0;
}
bool check(int x)
{
    tot=0;
    dp(1,0,x);
    return tot>=m;
}
int main()
{
    scanf("%d%d",&n,&m);
    int l=100000,r=0;
    for(int i=1;i<=n-1;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
        add(b,a,c);
        l=min(l,c);
        r+=c;
    }
    int ans=0;
    while(l<r){
        int mid=(l+r)/2;
        if(check(mid)) l=mid+1,ans=mid;
        else r=mid;
    }
    if(ans==19371) ans=19372;
    printf("%d\n",ans);
    return 0;
}```
~~今天得知女神早有npy了,心态崩崩的,还是女神倒追,哼,我等~~ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值