对于每个连通块,不同颜色的点可以连边;已有z条边,每条边连接都是不同颜色,所以贡献为x * y - z。
对于不同连通块,任意两点可以互相连边(颜色相同反一下即可)。

#include <stdio.h>
#define N 200005
int n, m, i, j, k, a, b, h[N], c[N], u[N*2];
long long s, x, y, z, p;
struct AB{
    int a, b, n;
} d[N*2];
void cun(int a, int b){
    d[++k].a = a, d[k].b = b;
    d[k].n = h[a], h[a] = k, u[k] = 1;
}
void dfs(int a){
    int b, i;
    x += c[a]<3, y += c[a]>2;//黑白分别多少个点
    for(i=h[a]; i; i=d[i].n){
        b = d[i].b, z += u[i];//有多少条边
        u[i] = u[i^1] = 0;
        if(!c[b]){
            c[b] = c[a] ^ 1;
            dfs(b);
        }
        else if(c[b] == c[a]) s = -1e18;//不是二分图
    }
}
int main(){
    scanf("%d%d", &n, &m);
    for(i=k=1; i<=m; i++){
        scanf("%d%d", &a, &b);
        cun(a, b);
        cun(b, a);
    }
    for(i=1; i<=n; i++){
        if(c[i]) continue;
        x = y = z = 0, c[i] = 2;
        dfs(i);
        s += x*y-z + p*(x+y), p += x+y;
    }//每个连通块为x+y-z,连通块任意两点可以连边
    if(s < 0) s = 0;
    printf("%lld\n", s);
    return 0;
}

作者 crxis

发表回复