题目大意:
给定一个无重边自环的无向图,问图中有多少对共边三元环。如:
(n,m
≤
100000)。
解题思路:
最朴素的思路是枚举每一条边看它在多少个三元环内,也就是该边两端点所连相同点的个数,设为cnt,那么就会产生 C2cnt 个共边三元环。这样的复杂度是O(nm)的。
但我们对于每个点,可以先把它连的点打上标记,再枚举所有与它相连且度比它小的点的边集来求每条边的贡献,可以证明这样的复杂度是O( mm−−√ )的。
考虑把点按度是否大于
m−−√
分为重轻点,那所有边可分为三种:
1.轻点连轻点:有O(m)条,但每个轻点的边集只有O(
m−−√
),总复杂度为O(
mm−−√
)。
2.重点连轻点:也有O(m)条,但会枚举轻点的边集,只有O(
m−−√
),总复杂度也为O(
mm−−√
)。
3.重点连重点:处理对于一个重点最多涉及O(m)条边,而共有O(
m−−√
)个重点,总复杂度也为O(
mm−−√
)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll unsigned long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=100005,M=400005;
int T,n,m,du[N],visit[N];
int tot,first[N],nxt[M],to[M];
ll ans;
void add(int x,int y)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y,du[y]++;
}
void solve(int u)
{
//memset(visit,0,sizeof(visit));
for(int e=first[u];e;e=nxt[e])visit[to[e]]=u;
for(int e=first[u];e;e=nxt[e])
{
int v=to[e];
if(du[v]<=du[u])
{
if(du[v]==du[u]&&v>u)continue;
int cnt=0;
for(int i=first[v];i;i=nxt[i])
if(visit[to[i]]==u)cnt++;
ans+=1ll*cnt*(cnt-1)/2;
}
}
}
int main()
{
//freopen("star.in","r",stdin);
//freopen("star.out","w",stdout);
int x,y;
T=getint();
while(T--)
{
ans=tot=0;
memset(first,0,sizeof(first));
memset(du,0,sizeof(du));
memset(visit,0,sizeof(visit));
n=getint(),m=getint();
while(m--)
{
x=getint(),y=getint();
add(x,y),add(y,x);
}
for(int i=1;i<=n;i++)
solve(i);
cout<<ans<<'\n';
}
return 0;
}