AT_joisc2014_j 電圧题解

题意:

给定一个 \(n\) 个点 \(m\) 条边的图。

定义一条边是合法的当且仅当存在一种黑白染色方式,使得除这条边外所有边的两个端点颜色不同,且这条边的两个端点的颜色相同。

求合法的边的个数。

\(n \le 10^5,m \le 2 \times 10^5\)

分析:

题目可以转换成求该图有多少条边满足删掉它后图变为二分图,且删去的边的两点在二分图中要在同一部中。

建出 DFS 生成树。

  • 删掉它后图变为二分图:这条边为所有奇环的交且不同时被奇环偶环覆盖。
  • 删去的边的两点在二分图中要在同一部中:不被偶环覆盖。

证明显然,从环被一条返祖边或两条返祖边分类讨论一下即可。

我的实现方法略有点复杂。还用 map 取重边。

因此时间复杂度为 \(O(n \log n)\)

代码:

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n, m, cnt, ans;
int Odd[N], Even[N], dep[N], z[N];
int siz[N];
int f1[N], f2[N]; //奇,偶
bool vis[N], vis2[N], vis3[N];
map<int, map<int, int>>f;
int Max[N];
vector<int>p[N];
void dfs(int x, int fa) {
	//cout << x << endl;
	vis[x] = 1;
	for(auto y : p[x]) {
		if(y == fa) continue;
		dep[x] = dep[fa] + 1;
		if(!vis[y]) dfs(y, x);
		else {
			if(dep[y] > dep[x]) continue;
			if((dep[x] - dep[y] + 1) % 2 == 1) {
				//cout << x << " -> " << y << endl;
				Even[x] = min(Even[x], dep[y]);
				Max[x] = max(Max[x], dep[y]);
				f1[x]++; f1[y]--;
				cnt++;
				siz[x]++;
			}
			else {
				Odd[x] = min(Odd[x], dep[y]);
				f2[x]++; f2[y]--;
			} 
		}
	}
}
void Get(int x, int fa) {
	vis2[x] = 1;
	for(auto y : p[x]) {
		if(y == fa || vis2[y]) continue;
		
		Get(y, x);
		Max[x] = max(Max[x], Max[y]);
		siz[x] += siz[y];
		z[x] = min(z[x], Even[y]);
		f1[x] += f1[y];
		f2[x] += f2[y];
		Even[x] = min(Even[x], Even[y]);
		Odd[x] = min(Odd[x], Odd[y]);
	}
}
void dfs2(int x, int fa) {
	vis3[x] = 1;
	for(auto y : p[x]) {
		if(y == fa) continue;
		if(vis3[y]) {
			//cout << "e";
			if(f[min(x, y)][max(x, y)] > 1) continue;
			if(dep[y] > dep[x]) continue;
			if((dep[x] - dep[y] + 1) % 2 == 0) continue;
			//cout << "look : " << x << " - > " << y << " " << z[x] << endl;
			if(Even[x] < dep[y] || z[x] <= dep[y]) continue;
			if(siz[x] == cnt && Max[x] <= dep[y]) ans++;
			continue;
		}
		dfs2(y, x);
		
		if(f[min(x, y)][max(x, y)] > 1) continue;
		//cout << x << " -> " << y << endl;
		if(Even[y] <= dep[x] && Odd[y] <= dep[x] || f2[y]) continue;
		if(f1[y] == cnt) ans++;
	}
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	cin >> n >> m;
	for(int i = 1, u, v; i <= m; i++) {
		cin >> u >> v;
		if(u > v) swap(u, v);
		f[u][v]++;
		if(f[u][v] > 1) continue;
		p[u].push_back(v);
		p[v].push_back(u);
	}
	for(int i = 1; i <= n; i++) Odd[i] = Even[i] = z[i] = 1e9;
	for(int i = 1; i <= n; i++)
		if(!vis[i]) dfs(i, 0);
	for(int i = 1; i <= n; i++)
		if(!vis2[i]) Get(i, 0);
	for(int i = 1; i <= n; i++)
		if(!vis3[i]) dfs2(i, 0);
	cout << ans << endl;
	return 0;
}
/*
4 5
1 2
1 3
1 4
2 4
3 4
*/
posted @ 2024-03-05 20:07  小超手123  阅读(5)  评论(0编辑  收藏  举报