边双+桥
重点在于 \(low[v]>dfn[u]\)
为什么呢?
因为回不去了,所以说是割边
画图理解一下就好了
割边把图分割为各个边双联通的子图,直接\(dfs\)出结果.
#include <bits/stdc++.h>
#define mod 23333
#define ll long long
#define F(i,i0,n) for(int i=i0;i<=n;i++)
#define N 6000005
#define M 6000005
using namespace std;
inline int rd(){
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int p[M],id=1;
struct edge{
int v,nt;
}e[M];
void add(int x,int y){
e[++id]={y,p[x]};
p[x]=id;
}
int n,m,a[N],dfn[N],low[N],num,val[N],c[N],cut[N],dcc;
void Tanjan(int u,int fa){
dfn[u]=low[u]=++num;
for(int i=p[u];i;i=e[i].nt){
int v=e[i].v;
if(!dfn[v]){
Tanjan(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])cut[i]=cut[i^1]=1;
}
else if(i!=(fa^1))low[u]=min(low[u],dfn[v]);
}
}
vector<int>ans[N];
void dfs(int x){
c[x]=dcc;
if(x)ans[dcc].push_back(x);
for(int i=p[x];i;i=e[i].nt){
int v=e[i].v;
if(c[v]||cut[i])continue;
dfs(v);
}
}
int d[N],s[N];
int main() {
n=rd(),m=rd();
F(i,1,m){
int x=rd(),y=rd();
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i])Tanjan(i,0);
for(int i=1;i<=n;i++){
if(!c[i]){
++dcc;
dfs(i);
}
}
//F(i,1,id)cout<<cut[i]<<' ';
//cout<<endl;
cout<<dcc<<endl;
F(i,1,dcc){
cout<<ans[i].size()<<' ';
for(int j=0;j<ans[i].size();j++){
cout<<ans[i][j]<<' ';
}
cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号