CF76A

最小生成树妙题。

观察一下数据范围,n200n\leq 200m2×104m\leq 2\times 10^4。大概是 O(nm)O(nm) 或者多个 log\log 的。

从暴力谈起,先按 gg 升序排序。然后枚举 gig_i 作为购买金币数量。然后将 s1sis_1\sim s_iKruskalKruskal,相当于每次加一条边。银币数量其实也就是最小生成树中最大的边权。

但是这样复杂度是 O(m2logm)O(m^2\log m) 的,想想该如何优化。了解下最小生成树的性质:只有 n1n-1 条边,是树。

此时找性质:有些边由于不优被放弃后,就不会成为树边了。因为最小生成树随着加边只会更优,如果之前都不在里面了,那么之后如果要用它,为什么不用原先更优秀的那个呢?

然后就可以把边的数量降至 O(n)O(n)。此时复杂度 O(mnlogn)O(mn\log n)。此时瓶颈在于排序,发现可以因为边集合有序,插入一个的复杂度其实只需要 O(n)O(n)。复杂度变成 O(mn)O(mn)。稳过。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 5e5+10;
int n,m,G,S,c;
struct Nd{
	int x,y,g,s;
}a[N],b[N];
int f[N];
int fi(int x) {
	return f[x] == x ? f[x] : f[x] = fi(f[x]); 
}
int cnt;
int ans = LONG_LONG_MAX;
void klska(int i) {
//	});
	long long p = 0; cnt = 0;
	for(int i=1;i<=n;i++) f[i] = i;
	for(int i=1;i<=c;i++) {
		int fx = fi(a[i].x), fy = fi(a[i].y);
		if(fx == fy) continue;
		f[fx] = fy; p=max(p,a[i].s); a[++cnt] = a[i];
	}
	c = cnt;
	if(cnt == n-1) {
		ans = min(ans,p*S+b[i].g*G);
	}
}
signed main() {
	cin>>n>>m>>G>>S;
	for(int i=1;i<=m;i++) {
		cin>>b[i].x>>b[i].y>>b[i].g>>b[i].s;
	}
	sort(b+1,b+m+1,[](Nd x,Nd y) {
		return x.g<y.g;
	});
	for(int i=1;i<=m;i++) {
		int p = c+1;
		while(p-1>0 && b[i].s<a[p-1].s) {
			a[p]=a[p-1];
			p--;
		}
		c++;
		a[p] = b[i];
		klska(i);
	}
	if(ans>4e18) cout<<-1;
	else
	cout<<ans;
	return 0;
}

本文作者:cjrqwq

本文链接:https://www.cnblogs.com/yfzqwq/p/18492763

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   cjrqwq  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
展开
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.