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;
}
posted @ 2018-12-18 21:28  King_George  阅读(311)  评论(0编辑  收藏  举报