定义
dfn[x]:DFN过程中到x点的时间
low[x]:最小的x能达到的点的dfn
当x进栈时dfn[x]=low[x]
part[x]:x所在的强连通分量
代码解释
//强连通分量
int tarjan(int x)
{
d[++tot]=x;//进栈
dfn[x]=low[x]=++dd;//初始化dfn[]以及low[]
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(!dfn[j])//当没走过j是,遍历j
{
tarjan(j);
low[x]=min(low[x],low[j]);//因为x可以走到j,所以更新low[]
}
else
if(!part[j])//只有当j还在栈中是才可以更新low。因为当j不在栈中时,j并不能遍历到x
low[x]=min(low[x],low[j]);
}
if(dfn[x]==low[x])//表示x无法回溯到更小的dfn
{
num++;//num表示强连通分量个数
while(dfn[d[tot]]>=dfn[x])//退栈,在栈中比x后进栈的节点都与x属于同一个强连通分量
{
part[d[tot--]]=num;
}
}
}
//人工栈代码
long long tarjan(long long x1)
{
z[top=1]=x1;
while(top)
{
long long x=z[top];
if(!dfn[x])
{
dfn[x]=low[x]=++tot;
d[++dd]=x;
}
long long i;
for(i=last[x];i;i=next[i])
{
if(!dfn[to[i]])
{
break;
}
else
if(!belong[to[i]])
low[x]=min(low[to[i]],low[x]);
}
if(!i && top>1)
low[z[top-1]]=min(low[z[top-1]],low[x]);
if(!i)
{
if(dfn[x]==low[x])
{
be++;
while(dd && low[d[dd]]>=dfn[x])
{
belong[d[dd]]=be;
sum[be]+=a[d[dd]];
dd--;
}
}
top--;
}
else
z[++top]=to[i];
}
}
//双连通分量
int tarjan(int x,int fa)
{
low[x]=dfn[x]=++tot;
d[++dd]=x;
for(int i=last[x];i;i=next[i])
{
int j=to[i];
if(i!=fa)//类似于强连通分量,只有保证不走来的边就可以了
{
if(!dfn[j])
{
tarjan(j,i^1);
low[x]=min(low[x],low[j]);
}
else
low[x]=min(low[x],low[j]);
}
}
if(low[x]==dfn[x])
{
num++;
while(low[d[dd]]>=dfn[x] && dd)
{
part[d[dd--]]=num;
sum[num]++;
}
}
}