首页 > 其他分享 >AT_abc352_e

AT_abc352_e

时间:2024-05-18 17:43:42浏览次数:29  
标签:int 最小 tot abc352 fa cx include

题意

给定一个有 \(n\) 个点的图,初始没有任何边。接下来有 \(m\) 次操作,每次操作给定一个大小为 \(k\) 的集合 \(S\) 和一个权值 \(c\),并对所有 \(u,v \in S\) 并且 \(u < v\) 的点 \(u,v\) 连上一条边权为 \(c\) 的边。\(m\) 次操作后,判断图的连通性,若图联通则需求出其最小生成树的边权总和。

思路

如果直接暴力建边,时间复杂度 \(O(n^2)\),不可接受。

仔细思考一下,其实发现并不需要这么多的边。具体地,对于一个大小为 \(k\) 的集合 \(S\),只需要连 \(k-1\) 条边。为什么呢?假设只有这 \(k\) 个点要求最小生成树,那么最后一定只选择 \(k-1\) 条边。换句话说,在求最小生成树的过程中,只要保证对于同一个 \(S\) 中的点有足够的边能够选择即可。

有了上面的结论后,这道题就不难了。先使用并查集判断连通性,再使用 Kruskal 或 Prim 算法求最小生成树即可。时间复杂度 \(O(n \log n)\)。

代码如下:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define int long long
using namespace std;
int n,m,cnt,c,a,b,fa[1000001];
int tot,ans;
struct E
{
	int u,v,w;
}e[1000001];
int cx( int x )
{
	if( x == fa[x] ) return x;
	return fa[x] = cx( fa[x] );
}
bool ck( void )
{
	int f = cx( 1 );
	for( int i = 2 ; i <= n ; i ++ )
		if( cx( i ) != f )
			return false;
	return true;
}
bool cmp( E x , E y )
{
	return x.w < y.w;
}
signed main()
{
	cin >> n >> m;
	for( int i = 1 ; i <= n ; i ++ )
		fa[i] = i;
	while( m -- )
	{
		cin >> cnt >> c;
		cin >> a;
		for( int i = 2 ; i <= cnt ; i ++ )
		{
			cin >> b;
			fa[cx( b )] = cx( a );
			tot ++;
			e[tot].u = a,e[tot].v = b,e[tot].w = c;
        }
	}
	if( !ck() )
	{
		cout << -1 << endl;
		return 0;
	}
	sort( e + 1 , e + tot + 1 , cmp );
	cnt = 0;
	for( int i = 1 ; i <= n ; i ++ )
		fa[i] = i;
	for( int i = 1 ; i <= tot ; i ++ )
	{
		int x = cx( e[i].u ),y = cx( e[i].v );
		if( x == y ) continue;
		fa[x] = y;
		ans += e[i].w;
		cnt ++;
		if( cnt == n - 1 ) break;
	}
	cout << ans;
	return 0;
}

标签:int,最小,tot,abc352,fa,cx,include
From: https://www.cnblogs.com/-lilong-/p/18199554

相关文章

  • AT_abc352_d
    看到题目后,第一反应便是暴力枚举确定\(i\)。但是看到了\(N\le2\times10^5\),这种想法便不合适了。观察题目第二个条件,不难发现其实真正合法的方案很少。于是可以转变方向,枚举题目要求的排列集合。想到这步,接下来就不难了。确定好原排列中被选的数后,需要求出它们的下标的最小......
  • 题解:AT_abc352_C [ABC352C] Standing On The Shoulders
    考场憋了很久,最后代码贼短……理想状态下,直接全排列解决问题。但是,\(1\len\le2\times10^5\),明显TLE,试都不用试的。咋优化呢?其实,前面的巨人只负责“打地基”,作为“塔尖儿”的巨人有且仅有1个。而前面地基随便排列,地基高度(他们的和)都不会变。所以,我们只需要枚举塔尖即......
  • ABC352
    Alink\(x\)停不到,\(y\)能停到。要先判断是从前往后还是从后往前。点击查看代码#include<bits/stdc++.h>usingnamespacestd;signedmain(){ intn,x,y,z; cin>>n>>x>>y>>z; if(x<=y){ if(z>x&&z<=y)cout<<......
  • ABC352
    A.AtCoderLine判断\(z\)是否出现在\(x\)和\(y\)之间即可代码实现n,x,y,z=map(int,input().split())ifx>y:x,y=y,xifx<z<y:print('Yes')else:print('No')B.Typing模拟代码实现#include<bits/stdc++.h......
  • AtCoder abc352
    EProblemStatementYouaregivenaweightedundirectedgraph$G$with$N$vertices,numbered$1$to$N$.Initially,$G$hasnoedges.Youwillperform$M$operationstoaddedgesto$G$.The$i$-thoperation$$(1\leqi\leqM)$$isasfollows:Youar......