zoukankan      html  css  js  c++  java
  • Agc011_C Squared Graph

    传送门

    题目大意

    给定$n$个点$m$条边的简单图(无重边无自环),将有序点对${a,b}$作为新的点,新产生的$n^2$个点中对于两个点,${a,b},{x,y}$,当且仅当原图中存在边$(a,x)$和$(b,y)$,则在新图中产生边$({a,b},{x,y})$。求新图中连通块数。

    题解

    想一想新图的两个点联通有什么条件,就能渐渐推理出这个很显然的性质。

    若新图中${a,b}$与${x,y}$连通,则在原图中:

    $a,x$连通,$b,y$连通。

    $a,x$之间和$b,x$存在一条长度相同的路径(可以不是简单路径)

    若$a,x$连通、$b,y$连通,当且仅当$a,x$间只存在长为奇数的路径,$b,y$之间只存在长为偶数的路径(或相反),在新图中${a,b}$,${b,y}$不连通。

    若两个原图连通块$A,B$,对于有的点$space a,space xin A$,$b,yin Bspace$,当且仅当$A,B$均不存在奇环时,即$A,B$均为二分图时才可能出现${a.b}$与${x,y}$不连通,且会在新的图中恰好分为$2$个连通块。

    我们需要特判单点(度数为$0$)的情况:对所有至少包含一个原图单点的新图的点,它一定自成一个连通块。

    计有$K$个度数为$0$的单点,有$P$个二分图连通块,$Q$个非二分图连通块,由于新图中每一个连通块一定有原图中的一个或两个连通块产生,我们可以直接计算答案。$$Ans=space K(2n-1)-K(K-1)space + space P^2space +space Q^2space +space 2 imes Pcdot Q$$

    注意新图中的点对是有序,即$(a,b)$与$(b,a)$不同,第一部分是包含一个读数为$0$的单点的点对数,接下来的两个是枚举前面的点和后面的点在哪一个原图的性质相同的连通块里,即(都有奇环或都没有),其中两个二分图会产生两组,所以要乘$2$。最后那个部分是枚举前后的点在不同的连通块中,因为前后有别所以要乘$2$。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 200020
    using namespace std;
    LL read(){
    	LL nm=0,fh=1; char cw=getchar();
    	for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
    	for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
    	return nm*fh;
    }
    LL ans,sum0,sum1,sig;
    LL n,m,fs[M],nt[M<<1],to[M<<1],col[M],f[M],sz[M],tmp;
    LL fd(LL x){return x==f[x]?x:f[x]=fd(f[x]);}
    void link(LL x,LL y){nt[tmp]=fs[x],fs[x]=tmp,to[tmp++]=y;}
    void merge(LL x,LL y){x=fd(x),y=fd(y);if(x!=y) f[x]=y,sz[y]+=sz[x];}
    bool check(LL x,LL now){
    	if(col[x]) return col[x]==now; col[x]=now;
    	for(LL i=fs[x];i!=-1;i=nt[i])
    		if(!check(to[i],3-now)) return false;
    	return true;
    }
    int main(){
    	n=read(),m=read(),memset(fs,-1,sizeof(fs));
    	for(LL i=1;i<=n;i++) f[i]=i,sz[i]=1;
    	for(LL i=1;i<=m;i++){
    		LL x=read(),y=read();
    		link(x,y),link(y,x),merge(x,y);
    	}
    	for(LL i=1;i<=n;i++) if(fd(i)==i&&sz[i]==1) sig++;
    	for(LL i=1;i<=n;i++){
    		if(fd(i)!=i||sz[i]==1) continue;
    		if(check(i,1)) sum0++;
    		else sum1++;
    	}
    	ans+=sig*((n<<1)-1)-sig*(sig-1);
    	ans+=((sum0*sum0)<<1);
    	ans+=sum1*(sum0<<1)+sum1*sum1;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    java 获取最近三个月的月初和月末日期
    java 字符串与十六进制互转
    @Validated 参数校验及配置
    mybatis 存取Oracle数据库中Blob类型数据
    Java下载服务器文件到前端
    Java实现Oracle拷贝数据插入到MySQL
    保利、绿地用移动质检3.0管进度、质量,让快周转又快又好!
    未造先知,匠心协同-BIM全过程总咨询实践案例赏析-2021版
    大数据资产管理总体框架概述
    “数据资产全生命周期管理”你要知道的九大问题
  • 原文地址:https://www.cnblogs.com/OYJason/p/9723974.html
Copyright © 2011-2022 走看看