Gym102028L
题意
给 \(n\) 个点 \(m\) 条边无向图。
多测,问有多少个边集 \(S\subset E\) 满足 \(|S|\ =\ 4,\ S\) 的导出子图联通。
\(4\ \leq\ n\ \leq\ 10^5,\ 4\ \leq\ m\ \leq\ 2\times 10^5\)。
做法1
满足 \(S\) 的点集只有五种情况:新戊烷、异戊烷、正戊烷、环丁烷、甲基环丙烷。
算异戊烷时,枚举 \(deg\ =\ 3\) 的那个点,会算两次甲基环丙烷。
算正戊烷时,枚举中间那个点,会算四次环丁烷、两次甲基环丙烷。
容斥一下即可。
三元环计数:
将点按照 \(size\) 排好序,枚举 \(u,\ v,\ w\) 满足 \(rnk_u\ <\ rnk_v\ <\ rnk_w\)。
四元环计数:
将点按照 \(size\) 排好序,枚举四元环的一半,枚举 \(u,\ v,\ w\) 满足 \(max(rnk_u,\ rnk_v)\ <\ rnk_w\)。
四元环复杂度与三元环类似。
总时间复杂度 \(O(m\ \sqrt{m})\)。
代码
#include <bits/stdc++.h>
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
template<int input_SZ, int output_SZ> struct IO {
char s[input_SZ], t[output_SZ], *a, *b;
IO() { fread(s, 1, input_SZ, stdin); a = s; b = t; }
~IO() { fwrite(t, 1, b - t, stdout); }
char nextchar() {
for(;;) {
if(*a >= 'A' && *a <= 'Z' || *a == '!' || *a == '?') return *a++;
a++;
}
}
int nextint() {
while(*a != '-' && (*a < '0' || *a > '9')) ++a;
bool flag = 0; int x = 0;
if(*a == '-') ++a, flag = 1;
while(*a >= '0' && *a <= '9') x = x * 10 + *a++ - '0';
if(flag) x = -x;
return x;
}
long long nextll() {
while(*a != '-' && (*a < '0' || *a > '9')) ++a;
bool flag = 0; long long x = 0;
if(*a == '-') ++a, flag = 1;
while(*a >= '0' && *a <= '9') x = x * 10 + *a++ - '0';
if(flag) x = -x;
return x;
}
void outchar(char c) {
*b++ = c;
if(b - t > output_SZ - 25) { fwrite(t, 1, b - t, stdout); b = t; }
return;
}
template<typename T> void outnum(T x) {
if(!x) { *b++ = '0'; return; }
if(x < 0) *b++ = '-', x = -x;
static char s[20], *a;
a = s;
while(x) {
T y = x / 10;
*a++ = x - y * 10 + '0';
x = y;
}
while(a != s) *b++ = *--a;
if(b - t > output_SZ - 25) { fwrite(t, 1, b - t, stdout); b = t; }
return;
}
template<typename T> void outnum(T x, char c) {
return outnum(x), outchar(c);
}
};
IO<(1 << 27) | 10, (1 << 20) | 10> io;
int main() {
ios::sync_with_stdio(false);
auto solve = [&]() {
static constexpr int mod = 1e9 + 7, maxn = 1e5 + 10, maxm = 2e5 + 10;
auto pow_mod = [&](int x, int n) {
int y = 1;
while(n) {
if(n & 1) y = (long long) y * x % mod;
x = (long long) x * x % mod;
n >>= 1;
}
return y;
};
int n, m;
n = io.nextint(), m = io.nextint();
int eu[maxm], ev[maxm], deg[maxn], ord[maxn], rnk[maxn];
vector<int> g[maxn];
for (int i = 0; i < n; ++i) ord[i] = i, g[i].clear(), deg[i] = 0;
for (int i = 0; i < m; ++i) {
eu[i] = io.nextint();
ev[i] = io.nextint();
++deg[--eu[i]];
++deg[--ev[i]];
}
sort(ord, ord + n, [&](int u, int v) { return deg[u] < deg[v]; });
for (int i = 0; i < n; ++i) rnk[ord[i]] = i;
for (int i = 0; i < m; ++i) g[rnk[eu[i]]].push_back(rnk[ev[i]]), g[rnk[ev[i]]].push_back(rnk[eu[i]]);
for (int i = 0; i < n; ++i) sort(g[i].begin(), g[i].end());
auto xinwuwan = [&]() {
int ret = 0;
int coef = pow_mod(24, mod - 2);
for (int u = 0; u < n; ++u) {
auto F = [&](int n) { return (long long) n * (n - 1) % mod * (n - 2) % mod * (n - 3) % mod * coef % mod; };
ret = (ret + F(g[u].size())) % mod;
}
return ret;
};
auto yiwuwan = [&]() {
int ret = 0;
for (int u = 0; u < n; ++u) {
auto F = [&](int n) { return ((long long) n * (n - 1) >> 1) % mod; };
for (int v: g[u]) ret = ((long long) (g[v].size() - 1) * F(g[u].size() - 1) + ret) % mod;
}
return ret;
};
auto zhengwuwan = [&]() {
int ret = 0;
for (int u = 0; u < n; ++u) {
int x = 0;
for (int v: g[u]) {
int y = g[v].size() - 1;
ret = ((long long) x * y + ret) % mod;
x = (x + y) % mod;
}
}
return ret;
};
auto huanjiwan = [&]() {
static int tmp[maxn];
memset(tmp, 0, sizeof(tmp[0]) * n);
int ret = 0;
for (int u = 0; u < n; ++u) {
for (int v: g[u]) {
for (int i = g[v].size() - 1; ~i; --i) {
int w = g[v][i];
if(w <= u || w <= v) break;
ret = (ret + tmp[w]) % mod;
++tmp[w];
}
}
for (int v: g[u]) {
for (int i = g[v].size() - 1; ~i; --i) {
int w = g[v][i];
if(w <= u || w <= v) break;
tmp[w] = 0;
}
}
}
return ret;
};
auto jiajihuanbingwan = [&]() {
static int tmp[maxn];
memset(tmp, -1, sizeof(tmp[0]) * n);
int ret = 0;
for (int u = 0; u < n; ++u) {
for (int i = g[u].size() - 1; ~i; --i) {
int v = g[u][i];
if(v <= u) break;
tmp[v] = u;
for (int j = g[v].size() - 1; ~j; --j) {
int w = g[v][j];
if(w <= v) break;
if(tmp[w] == u) ret = (ret + g[u].size() + g[v].size() + g[w].size() - 5) % mod;
}
}
}
return ret;
};
int ans = 0;
ans = (ans + xinwuwan()) % mod;
ans = (ans + yiwuwan()) % mod;
ans = (ans + zhengwuwan()) % mod;
ans = ((long long) ans - 3ll * huanjiwan()) % mod;
ans = ((long long) ans - 3ll * jiajihuanbingwan()) % mod;
cout << (ans + mod) % mod << endl;
return;
};
int T;
T = io.nextint();
while(T--) solve();
return 0;
}