ABC282D题解
思路
核心算法:二分图染色
如果不知道二分图染色的话,自己百度去。
首先,定义一个计数器 ,表示有多少组颜色相同的点对无法用边连起来。
注意,这个图不一定连通。
所以就遍历连通块进行二分图染色,如果不是二分图,直接输出 ,收工。
为什么?

如图,可以发现,无法只添加一个边使得图为二分图。
定义 为这个连通块黑点的个数, 为这个连通块黑点的个数。
那,如果是二分图,将这个连通块内的黑点的对数 和白点的对数 累加到 里边。
最后,输出 这个图的点对总量() 边数 (有 个点对已经相连)。
代码
#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);
}

浙公网安备 33010602011771号