点双连通分量[模板]

#include 
using namespace std;
const int maxn=2e5+10;
int n,m,cut[maxn];
struct edge{
	int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
	d[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
int low[maxn],dfn[maxn],stac[maxn],top,id,dc;
vector<int>dcc[maxn];
void tarjan(int u,int root)
{
	dfn[u]=low[u]=++id,stac[++top]=u;
	if( u==root&&!head[u] )//孤立点
	{
		dcc[++dc].push_back(u);
		return;	
	} 
	int flag=0;
	for(int i=head[u];i;i=d[i].nxt )
	{
		int v=d[i].to;
		if( !dfn[v] )
		{
			tarjan(v,root);
			low[u]=min( low[u],low[v] );
			if( low[v]>=dfn[u] )//不通过u,v无法回到更浅的节点
			{
				flag++;
				if( u!=root||flag>1 )	cut[u]=1;
				int temp; ++dc;//发现割点,开始弹栈 
				//注意,如果u是父节点且只有1个儿子,不算割点,但也会开始弹栈 
				while( temp=stac[top--] )
				{
					dcc[dc].push_back(temp);
					if( temp==v )	break;//直到遇到v 
				}
				dcc[dc].push_back(u);
			}	
		}
		else	low[u]=min(low[u],dfn[v] );
	}
}
int main()
{
	cin >> n >> m;
	for(int i=1;i<=m;i++)
	{
		int l,r; cin >> l >> r;
		add(l,r); add(r,l);
	}
	for(int i=1;i<=n;i++)
		if( !dfn[i] )	tarjan(i,i);
	for(int i=1;i<=dc;i++)
	{
		for(int j=0;j<dcc[i].size();j++)
			cout << dcc[i][j] << " ";
		cout << '\n';
	}
}

你可能感兴趣的:(我的模板类)