/*
1. 数组的初始化:当首次搜索到点p时,Dfn与Low数组的值都为到该点的时间。
2. 堆栈:每搜索到一个点,将它压入栈顶。
3. 当点p有与点p’相连时,如果此时(时间为dfn[p]时)p’不在栈中,p的low值为两点的low值中较小的一个。
4. 当点p有与点p’相连时,如果此时(时间为dfn[p]时)p’在栈中,p的low值为p的low值和p’的dfn值中较小的一个。
5. 每当搜索到一个点经过以上操作后(也就是子树已经全部遍历)的low值等于dfn值,则将它以及在它之上的元素弹出栈。
这些出栈的元素组成一个强连通分量。
6. 继续搜索(或许会更换搜索的起点,因为整个有向图可能分为两个不连通的部分),直到所有点被遍历。
*/
void tarjan(int u) {
dfn[ u ] = low[ u ] = indeu ++;
S.push(u);
instack[ u ] = true;
for(int i = p[ u ]; i != -1; i = e[ i ].neut) {
int v = e[ i ].v;
if(dfn[ v ] == -1) {
tarjan(v);
low[ u ] = min(low[ u ], low[ v ]);
}
else if(instack[ v ])
low[ u ] = min(low[ u ], dfn[ v ]);
}
if(low[ u ] == dfn[ u ]) {
while(true) {
int tmp = S.top();
S.pop();
belong[ tmp ] = cnt;
instack[ tmp ] = false;
if(tmp == u) break;
}
cnt ++;
}
}