洛谷P8435 【模板】点双连通分量 题解
题目链接:https://www.luogu.com.cn/problem/P8435
解题思路完全参考自 Jeremiahy 大佬的博客 。特别是文章的最后一部分。
(系统维护,博客点不进,那先直接进 https://www.luogu.com.cn/problem/solution/P8435)
注意:有 重边 和 自环!!
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
int n, m, dfn[maxn], low[maxn], idx, dcc, fat[maxn];
bool iscut[maxn];
vector<int> vec[maxn];
struct Node {
int id, v;
};
vector<Node> g[maxn];
stack<int> stk;
void new_dcc(int u, int x) {
dcc++;
int v;
do {
v = stk.top();
stk.pop();
vec[dcc].push_back(v);
} while (v != u);
if (u != x)
vec[dcc].push_back(x);
}
void tarjan(int u, int fe) {
dfn[u] = low[u] = ++idx;
int cnt = 0;
for (auto e : g[u]) {
int id = e.id, v = e.v;
if (!dfn[v]) {
fat[v] = id;
cnt++;
tarjan(v, id);
low[u] = min(low[u], low[v]);
if (low[v] >= dfn[u])
iscut[u] = true;
}
else if (id != fe)
low[u] = min(low[u], dfn[v]);
}
if (fe == -1 && cnt >= 2)
iscut[u] = true;
}
void dfs(int u) {
if (!fat[u] && g[u].size() == 0) { // 独根树
vec[++dcc].push_back(u);
return;
}
stk.push(u);
for (auto e : g[u]) {
int id = e.id, v = e.v;
if (fat[v] == id) {
dfs(v);
if (low[v] >= dfn[u] && iscut[u]) {
new_dcc(v, u);
}
}
}
if (!fat[u]) { // 根节点
if (stk.size() > 1)
new_dcc(u, u);
while (!stk.empty())
stk.pop();
}
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
if (u == v) continue; // 过滤掉重边
g[u].push_back({i, v});
g[v].push_back({i, u});
}
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i, -1), dfs(i);
printf("%d\n", dcc);
for (int i = 1; i <= dcc; i++) {
printf("%d", vec[i].size());
for (auto x : vec[i])
printf(" %d", x);
puts("");
}
return 0;
}