You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10, M = 4e6 + 10;
//链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
//点双需要的变量
int dfn[N], low[N], stk[N], timestamp, top;
vector<int> bcc[N];
int bcnt;
//点双模板1 【推荐】
void tarjan(int u, int fa) {
low[u] = dfn[u] = ++timestamp;
stk[++top] = u;
int son = 0; //子节点个数
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
// if (j == fa) continue; //这句看似无用dfn[j]可以包含,但事实证明,有些题会在后面加入其它代码造成执行逻辑错误,背模板时,加上这句保准!
if (!dfn[j]) {
son++; //找到一个子节点
tarjan(j, u);
low[u] = min(low[u], low[j]);
if (low[j] >= dfn[u]) {
int x;
bcnt++;
do {
x = stk[top--];
bcc[bcnt].push_back(x);
} while (x != j); //将子树出栈
bcc[bcnt].push_back(u); //把割点/树根也丢到点双里
}
} else
low[u] = min(low[u], dfn[j]);
}
//特判独立点
if (fa == -1 && son == 0) bcc[++bcnt].push_back(u);
}
int n, m;
int main() {
//文件输入输出
#ifndef ONLINE_JUDGE
freopen("P8435.in", "r", stdin);
#endif
//清空链式前向星
memset(h, -1, sizeof h);
scanf("%d %d", &n, &m);
while (m--) {
int a, b;
scanf("%d %d", &a, &b);
if (a != b) add(a, b), add(b, a); //此题目需要判断一下自环否则1和11会挂
}
//给定一个n个点m条边的无向图求该图中的所有点双连通分量(v-bcc)
for (int i = 1; i <= n; i++) //每个点做为根结点进行枚举
if (!dfn[i]) tarjan(i, -1);
printf("%d\n", bcnt);
for (int i = 1; i <= bcnt; i++) { //枚举每个双连通分量
printf("%d ", bcc[i].size());
for (int j = 0; j < bcc[i].size(); j++) //输出双连通分量中的点有哪些
printf("%d ", bcc[i][j]);
puts("");
}
return 0;
}