牛客小白月赛69 D-旅游(最小生成树+二分答案+点乘结论)

链接:登录—专业IT笔试面试备考平台_牛客网

题目描述

有 nnn 个城市,mmm 条连接两个城市的双向道路,每条道路有个损坏值 aia_iai​,牛牛手里有 ccc 元,进行第 kkk 次修复道路操作时需要 k×aik\times a_ik×ai​ 元,国家愿意修复损坏值 ≤p\le p≤p 的道路,牛牛不需要再花钱修国家帮忙修的路。问 ppp 至少为多少,牛牛有能力使得任意两座城市间可以通过修好的道路互相到达。如国家不需要修复任何道路,输出 000。

输入描述:

第一行三个正整数 n,m,c(1≤n≤4×104,1≤m≤105,1≤c≤1018)n,m,c(1\le n\le4\times10^4,1\le m\le10^5,1\le c\le10^{18})n,m,c(1≤n≤4×104,1≤m≤105,1≤c≤1018)。
接下来 mmm 行,每行 333 个正整数 x,y,ai(1≤x,y≤n,1≤ai≤109)x,y,a_i(1\le x,y\le n,1\le a_i\le10^9)x,y,ai​(1≤x,y≤n,1≤ai​≤109),表示有一条连接 x,yx,yx,y 城市的双向道路损坏值为 aia_iai​。保证无重边,无自环,图连通。

输出描述:

输出一行一个正整数,表示完成目标所需 ppp 的最小值。

示例1

输入

4 6 7
1 2 3
1 3 4
1 4 6
2 3 2
2 4 1
3 4 5

输出

1

说明

p=1p=1p=1 时,2,42,42,4 号城市可以互相到达,第一次操作修复连接 1,21,21,2 的道路,花费 1×31\times31×3 元,第一次操作修复连接 2,32,32,3 的道路,花费 2×22\times22×2 元,共花费 777 元,能达成目标。

由于题目要求最小满足条件的p值,故求最大满足条件的花费总和sum值,所以在指定范围的答案中向左二分,直到找到最小的p,故check中的条件为sum<=c的真值。其次,在每次构建最小生成树的时候都将小于等于p的边的权值定为0,这样既不影响后续的点乘处理,也解决了小于等于p的权重不需要纳入sum的问题。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,c;
struct p{
    int x,y;
    ll w;
}a[100001],b[100001];
int f[100001];
bool cmp(p a,p b)
{
    return a.w<b.w;
}
void init()
{
    for(int i=1;i<=n;i++)
        f[i]=i;
}
int find(int x)
{
    return x==f[x]?x:f[x]=find(f[x]);
}
bool check(int p)
{
    init();
    for(int i=0;i<m;i++)
    {
        b[i]=a[i];
        if(b[i].w<=p)
            b[i].w=0;
    }
    vector<ll> v,k;
    sort(b,b+m,cmp);
    for(int i=0;i<m;i++)
    {
        int fa=find(b[i].x);
        int fy=find(b[i].y);
        if(fa==fy)
            continue;
        f[fa]=fy;
        v.push_back(b[i].w);
        k.push_back(v.size());
    }
    sort(v.begin(),v.end());
    sort(k.begin(),k.end());
    reverse(v.begin(),v.end());
    ll sum=0;
    for(int i=0;i<v.size();i++)
    {
        sum+=v[i]*k[i];
    }
    return sum<=c;
}
int main()
{
    cin>>n>>m>>c;
    for(int i=0;i<m;i++)
    {
        cin>>a[i].x>>a[i].y>>a[i].w;
    }
    ll l=0,r=2e9;
    while(l<r)
    {
        ll mid=l+r>>1;
        if(check(mid))
            r=mid;
        else
            l=mid+1;
    }
    cout<<l<<endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值