int dfn[MAXN],cTime,low[MAXN]; //时间戳,时间戳计数,祖先时间。
int block[MAXN],bc; // 块数组,块计数。
int cut[MAXN];//记录每点属于几个割点块,注意根结点初始化为 0,其余
int ins[MAXN]; stack<int> sTar; //入栈标志,辅助栈
void Tarjan(int u, int fa ){
dfn[u]=low[u]=++cTime; //时间戳与祖先时间初始化
ins[u]=1; sTar.push(u); //入栈
for(int i=p[u];i;i=edge[i].next){ //递归处理所有子结点
int v=edge[i].v;
if(v == fa)continue; //如果是【u v】边跳过
if(!dfn[v]){
Tarjan(v,u);
low[u]=min(low[u],low[v]);//利用子孙,更新能回指的祖先
if(low[v]>=dfn[u]){ //如果u是割点
bc++;cut[u]++; //u属于的割点块+1
int i;block[u]=bc; //u点必定属于当前块,为了根结
do{
i=sTar.top(); ins[i]=0; //结点标记块号,块出
block[i]=bc; sTar.pop();
}while(i!=v);
}
}
else //记录U能回指的最早祖先的时间戳 if(ins[v])
low[u]=min(low[u],dfn[v]);
} }
int dfn[MAXN],cTime,low[MAXN]; //时间戳,时间戳计数,祖先时间。
int block[MAXN],bc; // 块数组,块计数。
int ins[MAXN]; stack<int> sTar; //入栈标志,辅助栈
void TarjanEdge(int u, int fa ){
dfn[u]=low[u]=++cTime; //时间戳与祖先时间初始化
ins[u]=1; sTar.push(u); //入栈
bool flag=1;
for(int i=p[u];i;i=edge[i].next){ //递归处理所有子结点
int v=edge[i].v;
if(v == fa && flag){flag=0; continue;} //跳过一条【u v】边
if(!dfn[v]){
TarjanEdge(v,u);
low[u]=min(low[u],low[v]); //利用子孙,更新能回指的祖
if(low[v]>dfn[u]){ //如果是割边
bc++;
int i;
do{
i=sTar.top(); ins[i]=0; //结点标记块号,块
block[i]=bc; sTar.pop();
}while(i!=v);
}
}
else //记录U能回指的最早祖先的时间戳 if(ins[v])
low[u]=min(low[u],dfn[v]);
}