题目描述
有 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;
}