边双+桥

重点在于 \(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;
}
posted @ 2023-09-09 17:09  ussumer  阅读(28)  评论(0)    收藏  举报