边双连通缩点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
const int N=2e6+5;
int n,m,u,v,_=1,tot,top,col;
int head[N],dfn[N],low[N],id[N],sta[N];
vector<int> ans[N];
inline int read()
{
int s=0,t=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*t;
}
struct node
{
int to,next;
}e[N<<1];
inline void add(int u,int v)
{
++_;
e[_].to=v;
e[_].next=head[u];
head[u]=_;
return;
}
inline void tarjan(int u)
{
dfn[u]=low[u]=++tot;
sta[++top]=u;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(i==id[u]) continue;
if(!dfn[v])
{
id[v]=i^1;
tarjan(v);
low[u]=min(low[u],low[v]);
if(dfn[u]<low[v])
{
++col;
for(int cur=0;cur!=v;) ans[col].push_back(cur=sta[top--]);
}
}
else low[u]=min(low[u],dfn[v]);
}
return;
}
int main()
{
n=read();
m=read();
while(m--)
{
u=read();
v=read();
add(u,v);
add(v,u);
}
for(int i=1;i<=n;++i)
if(!dfn[i])
{
tarjan(i);
++col;
for(int cur=0;cur!=i;) ans[col].push_back(cur=sta[top--]);
}
printf("%d\n",col);
for(int i=1;i<=col;++i)
{
int sz=ans[i].size();
printf("%d ",sz);
for(int j=0;j<sz;++j) printf("%d%c",ans[i][j]," \n"[j==sz-1]);
}
return 0;
}
点双连通缩点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#define mp make_pair
using namespace std;
const int N=2e6+5;
int n,m,u,v,cnt,tot,top,col;
int head[N],dfn[N],low[N],sta[N],bel[N];
bool vis[N];
vector<int> pos[N];
inline int read()
{
int s=0,t=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*t;
}
struct node
{
int to,next;
}e[N<<1];
inline void add(int u,int v)
{
++cnt;
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
return;
}
inline void tarjan(int u)
{
dfn[u]=low[u]=++tot;
sta[++top]=u;
vis[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
if(dfn[u]<=low[v])
{
++col;
for(int cur=0;cur!=v;)
{
bel[cur=sta[top--]]=col;
pos[col].push_back(cur);
vis[cur]=0;
}
bel[u]=col;
pos[col].push_back(u);
}
}
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
}
int main()
{
n=read();
m=read();
while(m--)
{
u=read();
v=read();
add(u,v);
add(v,u);
}
for(int i=1;i<=n;++i)
if(!dfn[i])
{
sta[top=0]=0;
tarjan(i);
if(!bel[i])
{
++col;
for(int cur=0;cur!=i;)
{
bel[cur=sta[top--]]=col;
pos[col].push_back(cur);
vis[cur]=0;
}
}
}
printf("%d\n",col);
for(int i=1;i<=col;++i)
{
printf("%d ",(int)pos[i].size());
int sz=pos[i].size();
for(int j=0;j<sz;++j) printf("%d%c",pos[i][j]," \n"[j==sz-1]);
}
return 0;
}
一些性质
- 强连通缩点后的编号是逆拓扑序。
- 强连通缩点后的图是 DAG;双连通缩点的图是树,所以无向图可以考虑在 dfs 树上解决。
- 保证强连通缩点后的结果相同的边是在 O ( n ) O(n) O(n) 级别的(“保证强连通缩点后的结果相同的边”是指改变 l o w [ ] low[] low[] 的边)。
- 将一个边双连通分量中的所有边定向后,一定是一个强连通分量。
dfs 树
1. ARC143D Bridges
无向图强连通
1. CF1361E James and the Chase
2. ARC092F Two Faced Edges
点双连通
1. CF521E Cycling City
题目
首先,两点之间有
3
3
3 条不相交的简单路径的条件严格强于点双的
2
2
2 条。所以满足条件的
u
u
u,
v
v
v 两点一定在同一个点双中。
首先可以注意到仅含有一条环的点双是不存在符合条件的点对的,进一步发现除了这种情况外的点双都含有符合条件。因为图中一定存在一个度
≥
3
\ge3
≥3 的点,假设这个点是
u
u
u。任选两个与
u
u
u 之间有相连的边的点,假设是
v
1
v_1
v1,
v
2
v_2
v2。可以证明,如果删去边
u
↔
v
1
u\leftrightarrow v_1
u↔v1 和
u
↔
v
2
u\leftrightarrow v_2
u↔v2 后的 dfs 树上
l
c
a
(
v
1
,
v
2
)
lca(v_1,v_2)
lca(v1,v2) 不是
u
u
u。因为如果出现这种情况
u
u
u 为割点。
假设
l
c
a
(
v
1
,
v
2
)
=
w
lca(v_1,v_2)=w
lca(v1,v2)=w,那么
3
3
3 条路径分别是
u
→
w
u\rightarrow w
u→w;
u
→
v
1
→
⋯
→
w
u\rightarrow v_1\rightarrow\cdots\rightarrow w
u→v1→⋯→w;
u
→
v
2
→
⋯
→
w
u\rightarrow v_2\rightarrow\cdots\rightarrow w
u→v2→⋯→w。
边双连通
1.CF555E Case of Computer Network
题目
首先有一个性质:
将一个边双连通分量中的所有边定向,一定是一个强连通分量。
那么先边双缩点,如果有向点对
(
s
,
t
)
(s,t)
(s,t) 中
s
s
s 和
t
t
t 属于同一个边双,那么一定可行。
考虑
s
s
s 和
t
t
t 不在同一个边双的情况。边双缩点后的图为树。考虑树上差分,记
t
a
g
[
i
]
[
0
/
1
]
tag[i][0/1]
tag[i][0/1] 表示
f
a
t
h
e
r
i
→
i
father_i\rightarrow i
fatheri→i 的边是否被要求为向上的边
/
/
/ 向下的边。
如果同时
t
a
g
[
i
]
[
0
]
≠
0
tag[i][0]\not=0
tag[i][0]=0,
t
a
g
[
i
]
[
1
]
≠
0
tag[i][1]\not=0
tag[i][1]=0,那么不合法,否则合法。注意特判
s
s
s,
t
t
t 不连通的情况。