P8436 【模板】边双连通分量

【模板】边双连通分量

题目描述

对于一个 \(n\) 个节点 \(m\) 条无向边的图,请输出其边双连通分量的个数,并且输出每个边双连通分量。

输入格式

第一行,两个整数 \(n\)\(m\)

接下来 \(m\) 行,每行两个整数 \(u, v\),表示一条无向边。

输出格式

第一行一个整数 \(x\) 表示边双连通分量的个数。

接下来的 \(x\) 行,每行第一个数 \(a\) 表示该分量结点个数,然后 \(a\) 个数,描述一个边双连通分量。

你可以以任意顺序输出边双连通分量与边双连通分量内的结点。

样例 #1

样例输入 #1

5 8
1 3
2 4
4 3
1 2
4 5
5 1
2 4
1 1

样例输出 #1

1
5 1 5 4 2 3

样例 #2

样例输入 #2

5 3
1 2
2 3
1 3

样例输出 #2

3
3 1 3 2
1 4
1 5

样例 #3

样例输入 #3

6 5
1 3
2 4
1 2
4 6
2 3

样例输出 #3

4
3 1 2 3
1 4
1 5
1 6

样例 #4

样例输入 #4

7 8
1 3
2 4
3 5
2 5
6 4
2 5
6 3
2 7

样例输出 #4

3
1 1
5 2 5 3 6 4
1 7

提示

样例四解释:

相同颜色的点为同一个连通分量。

注:本题中边双连通分量指删除分量的任意一条边,依然连通的分量。


数据范围:
对于 \(100\%\) 的数据,\(1 \le n \le 5 \times10 ^5\)\(1 \le m \le 2 \times 10^6\)

  • 对于其中 \(25\%\) 的数据,\(1 \le n \le 100\)\(1 \le m \le 500\)
  • 对于另外 \(25\%\) 的数据,\(1 \le n \le 5000\)\(1 \le m \le 5 \times 10^4\)
  • 对于另外 \(40\%\) 的数据,\(1 \le n \le 2\times 10^5\)\(1 \le m \le 5\times 10^5\)
  • 对于另外 \(10\%\) 的数据,\(1 \le n \le 5 \times10 ^5\)\(1 \le m \le 2 \times 10^6\)

本题不卡常,时间限制与空间限制均已开大,正确的解法均可通过。


惊喜:AC 后记得把鼠标放到测试点上看反馈信息,有惊喜哦。

ps:刚才发了点双连通分量的模板题,顺便把边双连通分量的也发一下,求边双连通分量的代码解释可以看这一篇博客

// Problem: P8436 【模板】边双连通分量
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P8436
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Created Time: 2022-07-22 15:03:11
// 
// Powered by CP Editor (https://cpeditor.org)

//fw
#include<iostream>
#include<cstdio>
#include<fstream>
#include<algorithm>
#include<cmath>
#include<deque>
#include<vector>
#include<queue>
#include<string>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<climits>
#define zp ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
#define pii pair <int, int>
#define endl '\n'
#define pb push_back
#define lc u<<1
#define rc u<<1|1
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=5e5+10,M=4e6+10;
int dfn[N],low[N],times,stk[N],top,dcc_cnt,n,m;
bool is_bridge[M];
vector<int>dcc[N];
int h[N],e[M],ne[M],idx;
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=h[a];
	h[a]=idx++;
}
void tarjan(int u,int from)
{
	dfn[u]=low[u]=++times;
	stk[++top]=u;
	
	for(int i=h[u];~i;i=ne[i])
	{
		int j=e[i];
		if(!dfn[j])
		{
			tarjan(j,i);
			low[u]=min(low[u],low[j]);
			if(dfn[u]<low[j])
			is_bridge[i]=is_bridge[i^1]=1;
		}
		else if (i!=(from^1))
	    	low[u]=min(low[u],dfn[j]);
	}
	if(low[u]==dfn[u])
	{
		++dcc_cnt;
		int y;
		do
		{
			y=stk[top--];
			dcc[dcc_cnt].push_back(y);
			
		}while(y!=u);
	}
}
int main()
{
    memset(h,-1,sizeof h);
    cin>>n>>m;
    while(m--)
    {
    	int a,b;
    	cin>>a>>b;
    	add(a,b);
    	add(b,a);
    }
    for(int i=1;i<=n;i++)
    	if(!dfn[i])
    		tarjan(i,-1);
    cout<<dcc_cnt<<endl;
    for(int i=1;i<=dcc_cnt;i++)
    {
    	cout<<dcc[i].size();
    	for(auto l:dcc[i])
    	cout<<" "<<l;
    	cout<<endl;
    }
    return 0;
}
posted @ 2022-07-22 15:18  Avarice_Zhao  阅读(136)  评论(0编辑  收藏  举报