强连通分量可以用Tarjan求
比两遍dfn大概快30%
定义一个栈
把点压进去,然后根据自己所能到的点,求出能到达的dfn序最小的点
由此得到从此点到low点中的点(在栈中)可以成为一个强连通分量
具体实现是当x点满足dfn==low时,将栈中的点全部弹出至x点;
可以证明每个点最多被弹出1次,每条边最多被遍历一次
复杂度为
O(n+m)
int col[N],sz[N],cnt,num,dfn[N],low[N];
bool mark[N];
int Sk[N],r;
void Tarjan(int x){
dfn[x]=low[x]=++num;
mark[x]=true;
Sk[++r]=x;
LFOR(i,x){
int y=To[i];
if(!dfn[y]){
Tarjan(y);
chk_mi(low[x],low[y]);
}
else if(mark[y])chk_mi(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
int y;
cnt++;
do{
y=Sk[r--];
col[y]=cnt;
sz[cnt]++;
mark[y]=false;
}while(y!=x);
}
}