各色Tarjan集合

#include<bits/stdc++.h>
using namespace std;
const int N=100000,M=200000;
//所有Tarjan都要:
// dfn[N],low[N],cnt=1,st,scc,zhan[N],top,前向星,vector<int>SCC[N]
//强连通 ,belong[N],inq[N]
//割边,边双 bridge[N], belong[N]
//点双,割点 cut[N],root
int dfn[N],low[N],cnt=1,zhan[N],top,st,belong[N],scc,head[N],root,n;
bool bridge[M],inq[N],cut[N];
vector <int>SCC[N];
struct bian
{
    int nxt,to;
}b[M];
void add(int from,int to)
{
    b[++cnt].nxt=head[from];
    b[cnt].to=to;
    head[from]=cnt;
}
void Tarjan1(int cur)//强连通
{
    dfn[cur]=low[cur]=++st;
    zhan[++top]=cur;inq[cur]=true;
    int i=head[cur],v;
    while(i!=0)
    {
        v=b[i].to;
        if(dfn[v]==0)
        {
            Tarjan1(v);
            low[cur]=min(low[cur],low[v]);
        }
        else
        {
            if(inq[v]==true)
            {
                low[cur]=min(low[cur],dfn[v]);
            }
        }    
        i=b[i].nxt;
    }
    if(low[cur]==dfn[cur])
    {
        scc++;
        int ding;
        do
        {
            ding=zhan[top];
            inq[ding]=false;
            zhan[top--]=0;
            belong[ding]=scc;
            SCC[scc].push_back(ding);
        }while(ding!=cur);
    }
}
void Tarjan2(int cur,int pre)//割边,边双 
{
    dfn[cur]=low[cur]=++st;
    zhan[++top]=cur;
    int i=head[cur],v;
    while(i!=0)
    {
        v=b[i].to;
        if(i!=pre)
        {
            if(dfn[v]==0)
            {
                Tarjan2(v,i^1);
                low[cur]=min(low[cur],low[v]);
                if(low[v]>dfn[cur])
                {
                    bridge[i]=bridge[i^1]=true;
                    scc++;
                    int ding;
                    do
                    {
                        ding=zhan[top];
                        zhan[top--]=0;
                        belong[ding]=scc;
                        SCC[scc].push_back(ding);
                    }while(ding!=v);
                }
            }
            else
                low[cur]=min(low[cur],dfn[v]);
        }
        i=b[i].nxt;
    }
}
void Tarjan3(int cur)
{
    dfn[cur]=low[cur]=++st;
    zhan[++top]=cur;
    int i=head[cur],v,child=0;
    while(i!=0)
    {
        v=b[i].to;
        if(dfn[v]==0)
        {
            child++;
            Tarjan3(v);
            low[cur]=min(low[cur],low[v]);
            if(low[v]>=dfn[cur])
            {
                if(root!=cur)
                    cut[cur]=true;    
                scc++;
                int ding;
                do
                {
                    ding=zhan[top];
                    zhan[top--]=0;
                    SCC[scc].push_back(ding);
                }while(ding!=v);
                SCC[scc].push_back(cur);
            }
        }
        else
            low[cur]=min(low[cur],dfn[v]);
        i=b[i].nxt;
    }
    if(cur==root&&child>=2)
    {
        cut[cur]=true;
    }
}
int main()
{
    for(int i=1;i<=n;i++)
    {
        if(dfn[i]==0)
            Tarjan1(i);
        if(dfn[i]==0)
        {
            Tarjan2(i,0);
            int ding; 
            while(top>0)
            {
                ding=zhan[top];
                zhan[top--]=0;
                SCC[scc].push_back(ding);
            }
        }
        if(dfn[i]==0)
            root=i,Tarjan3(i);
    }
    return 0;
}

特殊点:
强连通的出栈在函数末,进入条件low[cur]=dfn[cur],break条件ding!=cur,注意要维护是否在栈中的数组inq,dfn[v]!=0且inq[v]==true时,才能进入else语句中更新low[cur];

边双和割边出栈在Tarjan过程中的dfn[v]=0中,判断是low[v]>dfn[cur],break条件ding!=v,结束后要清栈;

割点和点双联通在Tarjan过程中的dfn[v]=0中,判断是low[v]>=dfn[cur],break条件ding!=v,注意求割点时,若cur=root且child>=2,为割点;

原文地址:https://www.cnblogs.com/HKHbest/p/13922912.html