题意:
给定一张无向图,求以下图形的方案数,点集或边集不同认为是不同方案
(点数和<=3e5,边数和<=6e5,数据组数<=300)
思路:
考虑中间的边,它组成的三元环中任选两个都能组成不同的满足要求的图案
因此跑一遍三元环统计出每条边能组成的三元环个数
偷懒用unordered_map可以卡时限过,最好用hash
代码:
#include<bits/stdc++.h>
#define LL long long
#define pii pair<LL,int>
#define fi first
#define se second
const int N = 3e5+10;
const int mod = 1e5+3;
using namespace std;
int num[N];
vector<int>G[N],pos;
vector< pii >M[mod];
inline LL code(LL a,LL b){if(a>b)swap(a,b);
return (a<<18)|b;
}
inline bool check(int a,int b){
LL k = code(a,b);int p = k % mod;
for(int i=0;i<M[p].size();i++)if(M[p][i].fi==k)return true;
return false;
}
inline void add(int a,int b){
LL k = code(a,b);int p = k % mod;
M[p].emplace_back(pii(k,0));
}
inline void add(int a,int b,bool f){
LL k = code(a,b);int p = k % mod;
for(int i=0;i<M[p].size();i++)if(M[p][i].fi==k){
++M[p][i].se;return ;
}
}
inline int read()
{
int x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)==2){pos.clear();
for(int i=1;i<=n;i++)G[i].clear();
for(int i=0;i<mod;i++)M[i].clear();
for(int i=0,s,e;i<m;++i){
s = read(); e = read();
G[s].emplace_back(e);add(s,e);
G[e].emplace_back(s);
}LL ans = 0 ; m = sqrt(m+0.5);
for(int i=1,a,b;i<=n;i++)
if(G[i].size()>m)pos.emplace_back(i);
else for(int j=0;j<G[i].size();j++)if(G[a=G[i][j]].size()>m||a>i)
for(int k=j+1;k<G[i].size();k++)if((G[b=G[i][k]].size()>m||b>i)&&check(a,b))
add(a,b,1),add(a,i,1),add(b,i,1);
for(int i=0,a,b,c;i<pos.size();i++)for(int j=i+1;j<pos.size();j++)if(check(a=pos[i],b=pos[j]))
for(int k=j+1;k<pos.size();k++)if(check(a,c=pos[k])&&check(b,c))
add(a,b,1),add(b,c,1),add(a,c,1);
for(int i=0;i<mod;i++)for(int j=0;j<M[i].size();j++)ans += 1LL * M[i][j].se * (M[i][j].se-1) / 2;
printf("%lld\n",ans);
}return 0;
}