博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Agc011_C Squared Graph
阅读量:5250 次
发布时间:2019-06-14

本文共 2145 字,大约阅读时间需要 7 分钟。

题目大意

给定$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 x\in A$,$b,y\in B\space$,当且仅当$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^2\space +\space Q^2\space +\space 2\times P\cdot Q$$

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

 

#include
#include
#include
#include
#include
#define LL long long#define M 200020using 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\n",ans); return 0;}

 

  

 

转载于:https://www.cnblogs.com/OYJason/p/9723974.html

你可能感兴趣的文章
史上最全面的汽车金融风控解决方案,拿走不谢(仁润)
查看>>
[PHP源码阅读]strpos、strstr和stripos、stristr函数
查看>>
【Python Programe】使用Python发送语音验证
查看>>
阿里云域名备案成功,网站可以成功访问啦。
查看>>
docker安装脚本
查看>>
log4net 使用笔记
查看>>
@WebServlet注解
查看>>
网站收集
查看>>
Servlet与JSP之间相互传值问题
查看>>
编译安装mysql5.7
查看>>
flask 在模板中渲染错误消息 --
查看>>
flask实战-个人博客-编写博客前台
查看>>
spring boot cloud
查看>>
Eclipse设置全局用户名
查看>>
列表类型内置方法
查看>>
Android高级图片滚动控件,编写3D版的图片轮播器
查看>>
包新建[hsp学习笔记]留言本的创建(第十三讲)
查看>>
金币能力UVA11292:Dragon of Loowater
查看>>
项目总结:文件上传(MVC uploadify)
查看>>
JavaScript自动计算并且保留两位小数
查看>>