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
*/