先放代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005, M = 5000005; // N:节点数,M:边数
int head[N], ver[M * 2], Next[M * 2]; // 邻接表存储图
int cut[N]; // cut[i]:节点 i 是否为割点
int dfn[N], low[N], st[N]; // dfn:时间戳,low:最早可到达时间,st:栈
int n, m, tot = 1, num, root, top, cnt; // tot:边数,num:时间戳,root:根节点,top:栈顶,cnt:点双连通分量数量
vector<int> dcc[N * 2]; // 存储每个点双连通分量的节点
void add(int x, int y) {
ver[++tot] = y, Next[tot] = head[x], head[x] = tot;
}
// Tarjan 算法实现,用于计算点双连通分量
void tarjan(int x) {
dfn[x] = low[x] = ++num;
st[++top] = x;
if (x == root && head[x] == 0) {
dcc[++cnt].push_back(x);
return;
}
int flag = 0;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if (!dfn[y]) {
tarjan(y);
low[x] = (low[x], low[y]);
(low[y] >= dfn[x]) {
flag++;
(x != root || flag > ) cut[x] = ;
cnt++;
z;
{
z = st[top--];
dcc[cnt].(z);
} (z != y);
dcc[cnt].(x);
}
} {
low[x] = (low[x], dfn[y]);
}
}
}
{
ios::();
cin.();
cin >> n >> m;
( i = ; i <= m; i++) {
x, y;
cin >> x >> y;
(x == y) ;
(x, y), (y, x);
}
( i = ; i <= n; i++) {
(!dfn[i]) root = i, (i);
}
cout << cnt << ;
( i = ; i <= cnt; i++) {
cout << dcc[i].();
( j = ; j < dcc[i].(); j++) cout << << dcc[i][j];
cout << ;
}
;
}


