AT_joisc2014_j 電圧題解

小超手123發表於2024-03-05

題意:

給定一個 \(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
*/

相關文章