题解:AT_abc350_d [ABC350D] New Friends

赛时分析错并查集复杂度导致 rating\tt rating1616

思路

根据样例,我们可以发现这个图可能会有许多连通块。

对于其中一个连通块分析:如果它不是一个完全连通块,那么把它变为完全连通块是最优的。

而一个完全连通块(有 nn 个节点)有 n(n1)2\dfrac{n(n-1)}{2} 条边,但是众所周知这之中有一些边,所以我们要把它们减掉。

怎么计算这之中的边数呢?预处理每个点的度数(即相连接的边数)。

处理到这个点就加上这个点的度数。

但是每一条边连着两个点,这意味着我们统计出来的边数是实际边数的 22 倍。

如此计算便能得出答案。

代码实现

有并查集和 bfs\tt bfs 两种写法,这里采用 bfs\tt bfs 写法。

#include<bits/stdc++.h>
using namespace std;
struct node{
	int u,v,nxt;
}e[400005];
int head[200005],cnt,vis[200005];
void add(int u,int v){
	e[++cnt].u=u;
	e[cnt].v=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
int n,m;
long long ans=0,du[200005];
queue<int>q;
long long bfs(int _){
	q.push(_);
	long long sum=0;
	long long summ=0;
	while(!q.empty()){
		int now=q.front();
		q.pop();
		if(vis[now])continue;
//		cout<<now<<endl;
		vis[now]=1;
		sum++;
		summ+=du[now];
		for(int i=head[now];i;i=e[i].nxt){
			if(!vis[e[i].v])q.push(e[i].v); 
		}
	}
	return sum*(sum-1)/2-summ/2;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		add(u,v);
		add(v,u);
		du[u]++;
		du[v]++;
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			ans+=bfs(i);
		} 
	}
	cout<<ans;
	return 0;
}
posted @   Weslie_qwq  阅读(5)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示