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\)。
subtask | \(n\) | \(m\) | 分值 |
---|---|---|---|
\(1\) | \(1 \le n \le 100\) | \(1 \le m \le 500\) | \(25\) |
\(2\) | \(1 \le n \le 5000\) | \(1 \le m \le 5 \times 10^4\) | \(25\) |
\(3\) | \(1 \le n \le 2\times 10^5\) | \(1 \le m \le 5\times 10^5\) | \(25\) |
\(4\) | \(1 \le n \le 5 \times10 ^5\) | \(1 \le m \le 2 \times 10^6\) | \(25\) |
数据更新
- \(2022/7/14\) 加强数据
- \(2022/11/26\) 新增 \(10\) 组较小的数据(\(1\le n, m \le 10\)),方便选手调试。
- \(2022/12/31\) 重组 \(subtask\),并加入若干组极端数据。
- \(2023/1/1\) 发现昨天新加入的数据数据出了问题,已修改。
本题不卡常,时间限制与空间限制均已开大,正确的解法均可通过。
惊喜:AC 后记得把鼠标放到测试点上看反馈信息,有惊喜哦。
#include<iostream>
#include<vector>
#include<stack>
#define int long long
using namespace std;
struct edge{int x,y;
};
const int N=5*1e5+5;
int n,m,t=0,cnt=0,low[N],dfsn[N],a,b;
vector<edge>v;
vector<int>h[N];
vector<int>dcc[N];
stack<int>s;
void dfs(int x,int fa){low[x]=dfsn[x]=++t;s.push(x);for(int i=0;i<h[x].size();i++){int j=h[x][i],y=v[j].y;if(!dfsn[y]){dfs(y,j);low[x]=min(low[x],low[y]);if(low[y]>dfsn[x]){++cnt;while(1){int z=s.top();s.pop();dcc[cnt].push_back(z);if(z==y)break;}}}else if(j!=(fa^1))low[x]=min(low[x],dfsn[y]);}
}
signed main(){cin>>n>>m;for(int i=0;i<m;i++){cin>>a>>b;v.push_back({a,b});h[a].push_back(v.size()-1);v.push_back({b,a});h[b].push_back(v.size()-1);}for(int i=1;i<=n;i++){if(!dfsn[i]){dfs(i,0);}if(!s.empty()){++cnt;while(!s.empty()){dcc[cnt].push_back(s.top());s.pop();}}}cout<<cnt<<endl;for(int i=1;i<=cnt;i++){cout<<dcc[i].size()<<" ";for(int j:dcc[i])cout<<j<<" ";cout<<endl;}return 0;
}