P8435 【模板】点双连通分量
作者:互联网
【模板】点双连通分量
题目描述
对于一个 \(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 2 3 4 5
样例 #2
样例输入 #2
5 3
1 2
2 3
1 3
样例输出 #2
3
1 4
1 5
3 1 2 3
样例 #3
样例输入 #3
6 5
1 3
2 4
1 2
4 6
2 3
样例输出 #3
4
2 6 4
2 4 2
3 3 2 1
1 5
样例 #4
样例输入 #4
7 8
1 3
2 4
3 5
2 5
6 4
2 5
6 3
2 7
样例输出 #4
3
2 7 2
5 5 2 4 6 3
2 3 1
提示
样例四解释:
相同颜色的点为同一个分量里的结点。
注意:点双连通分量的定义为无向图的极大点双连通子图,而不是去掉割点后分成的子图。
温馨提示:
-
如果您只得了 20 pts,可能是您没有特判孤立点,孤立点也算一个点双连通分量。
-
如果您 WA 了测试点 1 和 11,可能是没有判自环。
数据范围:
对于 \(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:求点双连通分量的具体解释可以看这一篇tarjan vDCC缩点 模板,发这篇博客是因为求vDCC的时候被自环搞了
代码
// Problem: P8435 【模板】点双连通分量
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P8435
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Created Time: 2022-07-22 14:00:43
//
// 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 h[N],e[M],ne[M],idx,n,m;
int dfn[N],low[N],times,stk[N],top,dcc_cnt,root;
vector<int>dcc[N];
bool cut[N];
void add(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++times;
stk[++top]=u;
if(u==root&&h[u]==-1)
{
dcc_cnt++;
dcc[dcc_cnt].push_back(u);
return;
}
int cnt=0;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
if(dfn[u]<=low[j])
{
cnt++;
if(u!=root||cnt>1)cut[u]=true;
++dcc_cnt;
int y;
do
{
y=stk[top--];
dcc[dcc_cnt].push_back(y);
}while(y!=j);
dcc[dcc_cnt].push_back(u);
}
}
else low[u]=min(low[u],dfn[j]);
}
}
int main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
while(m--)
{
int a,b;
cin>>a>>b;
if(a!=b)//自环会出问题!!!
{
add(a,b);
add(b,a);
}
}
for(root=1;root<=n;root++)
{
if(!dfn[root])
tarjan(root);
}
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;
}
标签:连通,le,点双,int,样例,P8435,include,模板,分量 来源: https://www.cnblogs.com/avarice/p/16505783.html