LGP8436 [LG TPLT] 边双连通分量 学习笔记

LGP8436 [LG TPLT] 边双连通分量 学习笔记

Luogu Link

题意简述

给定一个 \(n\)\(m\) 边的无向图。求其所有边双连通分量。

做法解析

我们仍用 \(\texttt{tarjan}\) 算法求解。其实,求解边双和求解强连通分量几乎是一致的:无向图 \(\texttt{DFS}\) 生成树上的一个强连通分量就对应原图上的一个双连通分量。

你可以理解为:无向图 \(\texttt{DFS}\) 生成树上有强连通分量,意味着它可以按某个方向“顺着”遍历整个分量里的点,而原图的边都是无向,也即双向的,意味着它也一定能“逆着”遍历完整个分量。

代码实现

#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=5e5+5;
int N,M,X,Y,ecnt;
vector<pii> Gr[MaxN];
void addudge(int u,int v){
    Gr[u].push_back({v,++ecnt});
    Gr[v].push_back({u,ecnt});
}
int tot,dfn[MaxN],low[MaxN],stk[MaxN],ktp,bcnt;
int bel[MaxN];vector<int> bcc[MaxN];
void tarjan(int u,int fe){
    dfn[u]=low[u]=++tot,stk[++ktp]=u;
    for(auto [v,ce] : Gr[u]){
        if(ce==fe)continue;
        if(!dfn[v])tarjan(v,ce),minner(low[u],low[v]);
        else if(!bel[v])minner(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        bcnt++;int v;
        do{v=stk[ktp--];bcc[bcnt].push_back(v),bel[v]=bcnt;}while(v!=u);
    }
}
int main(){
    readis(N,M);
    for(int i=1;i<=M;i++)readis(X,Y),addudge(X,Y);
    for(int i=1;i<=N;i++)if(!dfn[i])ktp=0,tarjan(i,0);
    writil(bcnt);
    for(int i=1;i<=bcnt;i++){
        writip(bcc[i].size());
        for(int j : bcc[i])writip(j);
        puts("");
    }
    return 0;
}
posted @ 2025-08-01 10:38  矞龙OrinLoong  阅读(5)  评论(0)    收藏  举报