题意
定义两个图的乘法是:点数为它们的乘积,新图中(x,y)到(z,w)有边,当且仅当第一个图(x,z)有边,第二个图(y,w)有边
给出一个无向图G,求它的平方的连通分量个数
题解
手动打表找规律大法好!
我们考虑相对一般点的情形:图A乘上图B
首先考虑那些孤点(即度数为0),设AB孤点个数为I
由于孤点不和任何点有连接,所以在新图中,它所对应的那一行(列)就肯定是独立的
也就是说,跟孤点有关的就是
I
A
I
B
+
I
A
(
N
B
−
I
B
)
+
I
B
(
N
A
−
I
A
)
I_AI_B+I_A(N_B-I_B)+I_B(N_A-I_A)
IAIB+IA(NB−IB)+IB(NA−IA)
在原图中的一个二分图,我们只能黑->白->黑地走,所以在对应的乘积上会有两个连通块
而非二分图则可以保证最后形成的是一个连通块
而二分图乘上非二分图,也是一个连通块
综上,答案就是
(P为非二分图数量,Q为二分图数量)
a
n
s
=
I
A
I
B
+
I
A
(
N
B
−
I
B
)
+
I
B
(
N
A
−
I
A
)
+
P
A
P
B
+
P
A
Q
B
+
Q
A
P
B
+
2
Q
A
Q
B
ans=I_AI_B+I_A(N_B-I_B)+I_B(N_A-I_A)+P_AP_B+P_AQ_B+Q_AP_B+2Q_AQ_B
ans=IAIB+IA(NB−IB)+IB(NA−IA)+PAPB+PAQB+QAPB+2QAQB
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1000000+5;
typedef long long ll;
struct node{
int u,v,nxt;
}edge[N*2];
int head[N],mcnt;
int du[N];
void add_edge(int u,int v){
mcnt++;
edge[mcnt].u=u;
edge[mcnt].v=v;
edge[mcnt].nxt=head[u];
head[u]=mcnt;
du[u]++;
}
ll I,P,Q;
bool tag[N];
bool vis[N];
bool flag;
void dfs(int u){
vis[u]=1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(!vis[v]){
tag[v]=tag[u]^1;
dfs(v);
}
else
if(tag[u]==tag[v])
flag=false;
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
for(int i=1;i<=n;i++){
if(vis[i])
continue;
if(du[i]==0){
I++;
continue;
}
flag=true;
dfs(i);
if(flag)
Q++;
else
P++;
}
ll ans=1ll*2*I*n-1ll*I*I+1ll*P*P+2ll*P*Q+2ll*Q*Q;
printf("%lld\n",ans);
}