F. Make It Connected(最小生成树+分析)

题目

题意:

    给定n个点,每个点都有权值a[i],给x,y加边的代价是两点的权值相加。在给出m条规则x,y,v,也可以利用规则对x,y加边,花费为v。要求将这些点连起来形成树的最小花费代价。
     1 n 2 1 0 5 , 0 m 2 1 0 5 , 1 a i 1 0 12 , 1 x , y n , 1 w 1 0 12 1≤n≤2⋅10^5, 0≤m≤2⋅10^5,1≤ai≤10^{12},1≤x,y≤n, 1≤w≤10^{12}

分析:

    显然就是一棵最小生成树,但是由于点数太多,我们不能考虑所有的边。分析一下可以知道其实每个点要使用第一条规则的话,必然是与权值最小的点相连。所以我们只需要考虑权值最小的点与别的点的边和规则2给出的边,跑最小生成树即可。

#include <iostream>
#include <vector> 
#include <algorithm>
using namespace std;

typedef long long ll;

int parent[200005];

struct edge{
	int x,y;
	ll v;
	edge(int a,int b,ll c)
	{
		x = a;
		y = b;
		v = c;
	}
	bool operator<(const edge&e)const
	{
		return v < e.v;
	}
};

vector<edge> a;

ll v[200005];

int find(int p)
{
	if( p == parent[p] ) return p;
	return parent[p] = find(parent[p]);
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin >> n >> m;
	ll ans = 0;
	int begin;
	ll minx = 1e18;
	for (int i = 1; i <= n; i++)
	{
		cin >> v[i];
		parent[i] = i;
		if( minx > v[i] )
		{
			minx = v[i];
			begin = i;
		}
	}
	for (int i = 1; i <= m; i++)
	{
		int x,y;
		ll v;
		cin >> x >> y >> v;
		a.push_back(edge(x,y,v));
	}
	for (int i = 1; i <= n; i++)
	{
		if( i == begin ) continue;
		a.push_back(edge(begin,i,v[begin]+v[i]));
	}
	sort(a.begin(),a.end());
	for (int i = 0; i < a.size(); i++)
	{
		int rootx = find(a[i].x);
		int rooty = find(a[i].y);
		if( rootx != rooty )
		{
			ans += a[i].v;
			parent[rootx] = rooty;
		}
	}
	cout << ans << '\n';
	return 0;
}

发布了132 篇原创文章 · 获赞 6 · 访问量 7918

猜你喜欢

转载自blog.csdn.net/weixin_44316314/article/details/105018303