ABC282D题解

思路

核心算法:二分图染色

如果不知道二分图染色的话,自己百度去。

首先,定义一个计数器 sumsum,表示有多少组颜色相同的点对无法用边连起来。

注意,这个图不一定连通。

所以就遍历连通块进行二分图染色,如果不是二分图,直接输出 00,收工。

为什么?

如图,可以发现,无法只添加一个边使得图为二分图。

定义 BB 为这个连通块黑点的个数,WW 为这个连通块黑点的个数。

那,如果是二分图,将这个连通块内的黑点的对数 B×(B1)÷2B\times(B-1)\div2 和白点的对数 W×(W1)÷2W\times(W-1)\div2 累加到 sumsum 里边。

最后,输出 这个图的点对总量(N×(N1)÷2N\times(N-1)\div2- sumsum - 边数 MM(有 MM 个点对已经相连)。

代码

#include<bits/stdc++.h>
using namespace std;
long long n,m,c[200010],num,k[3];
long long g;
int f[400010],nxt[400010],to[400010];
bool v;
void Color(int u,int fa,int now){
	if(c[u]&&c[u]!=now){
		v=1;
		return;
	}
	else if(c[u]) return;
	else{
		c[u]=now;
		k[now]++;
	}
	for(int i=f[u];i;i=nxt[i]){
		if(to[i]==fa) continue;
		if(now==1)
			Color(to[i],u,2);
		else if(now==2)
			Color(to[i],u,1);
	}
}
void add(int a,int b){
	to[++num]=b;
	nxt[num]=f[a];
	f[a]=num;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		add(a,b);
		add(b,a);
	}
	for(int i=1;i<=n;i++){
		if(!c[i]){
			memset(k,0,sizeof(k));
			v=0;
			Color(i,0,1);
			if(v) return !printf("0\n");
			g+=1ll*k[1]*(k[1]-1)/2+1ll*k[2]*(k[2]-1)/2;
		}
	}
	return !printf("%lld",1ll*n*(n-1)/2-g-m);
}
posted @ 2022-12-24 21:59  fengxiaoyi  阅读(28)  评论(0)    收藏  举报  来源