点双+割点

主要就是 $ dfn[u]<=low[v]$

#include <bits/stdc++.h>
#define mod 23333
#define ll long long
#define F(i,i0,n) for(int i=i0;i<=n;i++)
const int N = 5e5 + 10, M = 4e6 + 10;
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;
struct edge{
    int u,v,nt;
}e[M];

inline void add(int x,int y){
    e[++id]={x,y,p[x]};
    p[x]=id;
}
int n,m,a[N],dfn[N],low[N],num,val[N],cut[N],cutlen;
int st[N],top;
vector<int>ans[N];
int len;
void Tanjan(int u,int fa){
    dfn[u]=low[u]=++num;
    if(u==fa&&!p[u]){
        ans[++len].push_back(u);
        return ;
    }
    st[++top]=u;
    for(int i=p[u];i;i=e[i].nt){
        int v=e[i].v;
        if(!dfn[v]){
            Tanjan(v,fa);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v]){
                ans[++len].push_back(u);
                int y;
                do{
                    y=st[top--];
                    ans[len].push_back(y);
                }while(y!=v);
            }
        }
        else low[u]=min(low[u],dfn[v]);
    }
}
int main() {
    n=rd(),m=rd();
    F(i,1,m){
        int x=rd(),y=rd();
        if(x==y)continue;
        add(x,y);
        add(y,x);
    }   
    for(int i=1;i<=n;i++)
        if(!dfn[i])Tanjan(i,i);
    printf("%d\n",len);
    F(i,1,len){
        printf("%d ",ans[i].size());
        for(int j=0;j<ans[i].size();j++)printf("%d ",ans[i][j]);
        printf("\n");
    }
    return 0;
}
posted @ 2023-09-09 17:08  ussumer  阅读(25)  评论(0)    收藏  举报