[图论] [切边等价] 题解:P6914 [ICPC 2015 WF] Tours

posted on 2025-03-20 08:36:00 | under | source

题意:给一张简单无向图,求有多少个 \(k\),满足可以为边染上 \(k\) 种颜色的一种,使得任意简单环每种颜色边的数量相同。\(n,m\le 2\times 10^3\)

对于若干不相交简单环构成的复合环不用管,因为子环合法它也合法。

然后考虑两个相交的简单环 \(A,B\),必然存在环 \(A\oplus B\)。拆为三部分 \(A\cap B,A-A\cap B,B-A\cap B\),则任选其二都能构成一个简单环。猜测 \(A,B,A\oplus B\) 合法当且仅当这三部分合法。充分性显然,必要性反证即可。

对于两个相交的“残缺”的链或环(即进行分解得来的部分),也能这样分解,证明考虑补上残缺的部分、对它们原先属于的环讨论即可。不断递归该过程,直到划分为若干不相交部分,显然 \(k\) 合法当且仅当 \(k\) 是每个独立边集大小的公约数。

不难发现,划分的结果和切边等价的等价类划分完全一致。注意丢掉割边(不出现在简单环上)。经典套路可以 \(O(n+m)\),不过排序需要 \(O(m\log m)\)

代码

偷懒写了 \(O(n^2)\)

#include<bits/stdc++.h>
using namespace std;

#define ull unsigned long long
#define pir pair<int, int>
const int N = 2e3 + 5;
int n, m, u, v, ans, dfn[N], df;
ull w[N];
mt19937 rnd(time(0));
vector<int> s;
vector<pir> to[N];
pir fa[N];
 
inline void dfs(int u, int from){
	dfn[u] = ++df;
	for(auto _ : to[u]){
		int v = _.first, id = _.second;
		if(v == from) continue;
		if(!dfn[v]) fa[v] = {u, id}, dfs(v, u);
		else if(dfn[v] < dfn[u]){
			w[id] = rnd();
			int now = u;
			while(now ^ v){
				pir __ = fa[now];
				w[__.second] ^= w[id];
				now = __.first;
			}
		}
	}
}
signed main(){
	cin >> n >> m;
	for(int i = 1; i <= m; ++i) scanf("%d%d", &u, &v), to[u].push_back({v, i}), to[v].push_back({u, i});
	for(int i = 1; i <= n; ++i) if(!dfn[i]) dfs(i, 0);
	sort(w + 1, w + 1 + m);
	for(int i = 1, ct = 0; i <= m; ++i){
		++ct;
		if(i == m || w[i] != w[i + 1]){
			if(w[i] > 0) s.push_back(ct);
			ct = 0;
		}
	}
	for(int i = 1; i <= m; ++i){
		bool fl = true;
		for(auto j : s) fl &= (j % i == 0);
		if(fl) printf("%d ", i);
	}
	return 0;
}

posted @ 2026-01-13 11:21  Zwi  阅读(0)  评论(0)    收藏  举报