//Tarjan求割点
void tarjan(int now,int fa){
int num=0;
low[now]=dfn[now]=++dfnc;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tarjan(u,now);
low[now]=min(low[now],low[u]);
if((fa==-1 && ++num>1) || (fa!=-1 && low[u]>=dfn[now])){
cut[now]=1;
}
}
else if(u!=fa){
low[now]=min(low[now],dfn[u]);
}
}
}
//Tarjan求点双
void tarjan(int now,int fa){
low[now]=dfn[now]=++dfnc;
sta[++top]=now;
for(int i=head[now];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tarjan(u,now);
low[now]=min(low[now],low[u]);
if(dfn[now]<=low[u]){
++num;
while(sta[top+1]!=u){
int w=sta[top--];
dcc[num].push_back(w);
}
dcc[num].push_back(now);
}
}
else if(u!=fa){
low[now]=min(low[now],dfn[u]);
}
}
}
//Tarjan点双缩点(圆方树)
void tarjan(int xx,int fa){
dfn[xx]=low[xx]=++dfc;
sta[++top]=xx;
num++;
for(int i=head[xx];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tarjan(u,xx);
low[xx]=min(low[xx],low[u]);
if(low[u]>=dfn[xx]){
n++;
ad2(xx,n),ad2(n,xx);
while(1){
int da=sta[top--];
ad2(da,n),ad2(n,da);
if(da==u) break;
}
}
} else if(u!=fa){
low[xx]=min(low[xx],dfn[u]);
}
}
}