题解:AT_abc350_d [ABC350D] New Friends
赛时分析错并查集复杂度导致 减 。
思路
根据样例,我们可以发现这个图可能会有许多连通块。
对于其中一个连通块分析:如果它不是一个完全连通块,那么把它变为完全连通块是最优的。
而一个完全连通块(有 个节点)有 条边,但是众所周知这之中有一些边,所以我们要把它们减掉。
怎么计算这之中的边数呢?预处理每个点的度数(即相连接的边数)。
处理到这个点就加上这个点的度数。
但是每一条边连着两个点,这意味着我们统计出来的边数是实际边数的 倍。
如此计算便能得出答案。
代码实现
有并查集和 两种写法,这里采用 写法。
#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;
}

浙公网安备 33010602011771号