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);
        }
    }
posted @ 2025-09-02 16:15  Marinaco  阅读(6)  评论(0)    收藏  举报
//雪花飘落效果