我会了Tarjan,会了强连通分量,会了缩点,会了割点,会了割边,会了边双连通分量,唯独不会点双,多年来的一块心病。
#include<bits/stdc++.h>
using namespace std;
vector<int> a[500010];
bool use[500010];
int dfn[500010],low[500010];
stack<int> s;
int cnt;
int ans;
vector<int> dot[500010];
int root;
void tarjan(int x)
{
use[x]=1;
dfn[x]=low[x]=++cnt;
if(a[x].size()==0&&root==x)
{
dot[++ans].push_back(x);
return ;
}
s.push(x);
for(int i=0;i<a[x].size();i++)
{
if(!dfn[a[x][i]])
{
tarjan(a[x][i]);
low[x]=min(low[x],low[a[x][i]]);
if(dfn[x]<=low[a[x][i]])
{
ans++;
int t;
do
{
t=s.top();
s.pop();
dot[ans].push_back(t);
}
while(t!=x);
s.push(x);
}
}
else
low[x]=min(low[x],dfn[a[x][i]]);
}
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
if(x==y)
continue;
a[x].push_back(y);
a[y].push_back(x);
}
for(int i=1;i<=n;i++)
if(!use[i])
root=i,tarjan(i);
cout<<ans<<endl;
for(int i=1;i<=ans;i++)
{
cout<<dot[i].size()<<' ';
for(int j=0;j<dot[i].size();j++)
cout<<dot[i][j]<<' ';
cout<<endl;
}
return 0;
}