Tarjan求点双连通分量 + 边双连通分量板子
求点双连通分量
int n,m;
vector<int>e[maxn];
int low[maxn];
int dfn[maxn];
int tot,cnt;
vector<int>ds[maxn];
int stk[maxn];
int top;
void dfs(int u,int fa){
low[u]=dfn[u]=++tot;
stk[++top]=u;
int son=0;
for(int v:e[u]){
if(!dfn[v]){
dfs(v,u);
++son;
low[u]=min(low[u],low[v]);
if(fa==0&&son>1||low[v]>=dfn[u]){
++cnt;
while(stk[top+1]!=v){
ds[cnt].pb(stk[top--]);
}
ds[cnt].pb(u);
}
}else if(v!=fa){
low[u]=min(low[u],dfn[v]);
}
}
if(fa==0&&son==0)ds[++cnt].pb(u);
}
...
rep(i,1,n){
if(!dfn[i]){
top=0;
dfs(i,0);
}
}
求边双连通分量:这个简单,易知边双连通分量不存在割边,因此只需要将割边都标记出来,然后搜索感染即可
int n,m;
vector<pii>e[maxn];
int tot;
int cnt;
int Cnt;
int dfn[maxn],low[maxn];
int bs[maxn];
int vis[maxn];
void dfs(int u,int fa){
low[u]=dfn[u]=++tot;
for(auto[v,bj]:e[u]){
if(v==fa)continue;
if(!dfn[v]){
dfs(v,u);
low[u] = min(low[u],low[v]);
if(low[v]>dfn[u]){
vis[bj] = 1;
}
}else {
low[u] =min(low[u],dfn[v]);
}
}
}
void split(int u,int p){
bs[u]=p;
for(auto[v,bj]:e[u]){
if(vis[bj])continue;
if(bs[v])continue;
split(v,p);
}
}
...
rep(i,1,n){
if(!dfn[i]){
dfs(i,0);
}
}
rep(i,1,n){
if(!bs[i]){
split(i,++Cnt);
}
}

浙公网安备 33010602011771号