题意
传送门 Codeforces 962F Simple Cycles Edges
题解
任一个简单环,都可以通过取 D F S DFS DFS 树单条非树边与树边构成的环的集合 S S S 的任意子集异或得到。一条边仅包含于一个简单环,当且仅当其所在环上的任一边仅包含于这个环。
那么可以构造 D F S DFS DFS 树,进行树上边差分,统计树边被非树边(返祖边)覆盖的次数。然后枚举非树边判断其所在环是否满足条件即可。总时间复杂度 O ( m ) O(m) O(m)。
也可以通过 T a r j a n Tarjan Tarjan 算法,判断各 v v v- D C C DCC DCC 是否仅存在单个环, O ( m ) O(m) O(m) 求解。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, l, r) for (int i = l, _ = r; i < _; ++i)
#define pb push_back
typedef long long ll;
const int MAXN = 1E5 + 5;
int N, M, dep[MAXN], sum[MAXN], par[MAXN], e_id[MAXN];
ll f[MAXN];
struct edge
{
int from, to;
} es[MAXN];
struct edge2
{
int to, id;
};
vector<edge2> G[MAXN];
vector<int> res;
void dfs(int u, int p, int d)
{
dep[u] = d, par[u] = p;
for (auto &e : G[u])
{
int v = e.to;
if (dep[v] == -1)
{
dfs(v, u, d + 1);
sum[u] += sum[v];
e_id[v] = e.id;
}
else if (v != p)
{
if (dep[u] < dep[v])
continue;
++sum[u], --sum[v];
}
}
}
void get(int u, int s)
{
f[u] = s;
for (auto &e : G[u])
{
int v = e.to;
if (dep[v] - dep[u] == 1)
get(v, s + (sum[v] > 1 ? MAXN : sum[v]));
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N >> M;
rep(i, 0, M)
{
int u, v;
cin >> u >> v;
--u, --v;
G[u].pb({v, i}), G[v].pb({u, i});
es[i] = {u, v};
}
memset(dep, -1, sizeof(dep));
rep(i, 0, N) if (dep[i] == -1) dfs(i, -1, 0), get(i, 0);
rep(i, 0, M)
{
int u = es[i].from, v = es[i].to;
if (dep[u] > dep[v])
swap(u, v);
if (dep[v] - dep[u] == 1)
continue;
if (f[v] - f[u] == dep[v] - dep[u])
{
res.pb(i);
int t = v;
while (t != u)
res.pb(e_id[t]), t = par[t];
}
}
sort(res.begin(), res.end());
cout << (int)res.size() << '\n';
rep(i, 0, res.size()) cout << res[i] + 1 << (i + 1 == (int)res.size() ? '\n' : ' ');
return 0;
}