边双连通分量
#include<bits/stdc++.h>
using namespace std;
const int M=2e6+10,N=5e5+10;
int n,m;
struct EDGE{int to,next;}ee[M];
int head[N],ne=1,nm;
inline void ae(int from,int to) {ee[++ne]={to,head[from]}, head[from]=ne;}
inline void fred() {ios::sync_with_stdio(); cin.tie(0), cout.tie(0);}
int dfn[N],low[N],st[N],g[N],top,ans;
inline void dfs(int from,int e) {
dfn[from]=low[from]=++nm;
st[++top]=from;
for(int i=head[from];i;i=ee[i].next) {
int to = ee[i].to;
if(!dfn[to]) {
dfs(to,i);
low[from]=min(low[from],low[to]);
if(low[to]>dfn[from]) {
g[i]=g[i^1]=1;
}
}
else if(i!=(e^1)) low[from]=min(low[from],dfn[to]);
}
if(low[from]==dfn[from]) {
ans++;
int p;
do {
p=st[top--];
} while(p^from);
}
}
int main() {
fred();
cin>>n>>m;
for(int i=1,x,y;i<=m;i++) {
cin>>x>>y;
ae(x,y), ae(y,x);
}
dfs(1,-1);
cout<<ans;
return 0;
}
点双连通分量
#include<bits/stdc++.h>
using namespace std;
inline void fred() {ios::sync_with_stdio(); cin.tie(0), cout.tie(0);}
const int M=2e6+10,N=5e5+10;
int n,m,nm;
int dfn[N],low[N],st[N],id[M<<1],top,ans,root;
vector<int>as[N],ee[N];
inline void dfs(int from) {
dfn[from]=low[from]=++nm; st[++top]=from;
if(from==root&&ee[from].empty()) {
as[++ans].push_back(from);
return ;
}
for(int to:ee[from]) {
if(!dfn[to]) {
dfs(to);
low[from]=min(low[from],low[to]);
if(low[to]>=dfn[from]) {
++ans; int p;
do
as[ans].push_back(p=st[top--]);
while(p!=to);
as[ans].push_back(from);
}
}
else low[from]=min(low[from],dfn[to]);
}
}
inline void print() {
cout<<ans<<"\n";
for(int i=1;i<=ans;i++) {
cout<<as[i].size()<<" ";
for(int j:as[i])
cout<<j<<" ";
cout<<"\n";
}
}
int main() {
fred();
cin>>n>>m;
for(int i=1,x,y;i<=m;i++) {
cin>>x>>y;
if(x!=y) ee[x].push_back(y), ee[y].push_back(x);
}
for(int i=1;i<=n;i++) if(!dfn[i]) root=i,dfs(i);
print();
return 0;
}