Decription
求一个无向图有多少个子图包含四个点,五条边。无重边自环。
n⩽300000,m⩽600000n⩽300000,m⩽600000
Solution
题意转化为统计每条边被多少三元环覆盖,答案就是∑C(cnti,2)∑C(cnti,2),cnticnti表示第ii条边被多少三元环覆盖。
将无向图重定向,度数小的点连向度数大的点,度数相同的点连向编号大的点。
这样可以保证每个点的出度是的。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 300005, maxm = 600005;
int n, m, cnt[maxn];
long long ans;
struct Edge {
int u, v;
}E[maxm];
struct edge {
int to, next;
}e[maxm * 2];
int h[maxn], tot, in[maxn], vis[maxn], to[maxn];
inline void add(int u, int v)
{
e[++tot] = (edge) {v, h[u]};
h[u] = tot;
}
int main()
{
freopen("stars.in", "r", stdin);
freopen("stars.out", "w", stdout);
while (scanf("%d%d", &n, &m) == 2) {
for (int i = 1; i <= m; ++i) {
scanf("%d%d", &E[i].u, &E[i].v);
++in[E[i].u]; ++in[E[i].v];
}
fill(h + 1, h + n + 1, 0); tot = 0;
for (int i = 1; i <= m; ++i) {
if (in[E[i].u] > in[E[i].v] || (in[E[i].u] == in[E[i].v] && E[i].u > E[i].v)) swap(E[i].u, E[i].v);
add(E[i].u, E[i].v);
}
fill(cnt + 1, cnt + m + 1, 0);
fill(vis + 1, vis + n + 1, 0);
ans = 0;
for (int j = 1; j <= m; ++j) {
for (int u = E[j].u, i = h[u]; i; i = e[i].next) vis[e[i].to] = j, to[e[i].to] = i;
for (int u = E[j].v, i = h[u]; i; i = e[i].next)
if (vis[e[i].to] == j) ++cnt[i], ++cnt[to[e[i].to]], ++cnt[j];
}
for (int i = 1; i <= m; ++i)
ans += (long long)cnt[i] * (cnt[i] - 1) / 2;
printf("%lld\n", ans);
}
return 0;
}