标签:连通 编号 pre 割点 双连通 next lan 竞赛 建立
//Tarjan求割点
void tarjan(int x){
int ch=0;
dfn[x]=low[x]=++dfnc;
for(int i=head[x];i!=-1;i=b[i].next){
int u=b[i].to;
if(!dfn[u]){
tarjan(u);
low[x]=min(low[x],low[u]);
if(low[u]>=dfn[x] && (rt!=x || ++ch>1)){
cut[x]=1;
}
} else {
low[x]=min(low[x],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点双缩点
/*
点双缩点比边双缩点要复杂一些
因为一个割点可能属于多个点双
我们设图中共有p个割点和t个点双
我们要建立一个含有p+t个节点的新图
我们把每一个点双和每一个割点都作为新图中的节点
并在每一个割点和包含它的所有点双之间建边
容易发现,这张新图实际上是一棵树
----李煜东《算法竞赛进阶指南》
*/
//给每一个割点新的编号
num=cnt;
for(int i=1;i<=n;i++){
if(cut[i]) new_id[i]=++num;
}
//建新图,从每个点双到它包含的所有割点连边
for(int i=1;i<=cnt;i++){
for(int j=0;j<dcc[i].size();j++){
int x=dcc[i][j];
if(cut[x]){
ad(i,new_id[x]);
ad(new_id[x],i);
} else {
c[x]=i;
}
}
}
标签:连通 编号 pre 割点 双连通 next lan 竞赛 建立
原文地址:https://www.cnblogs.com/liuchanglc/p/12812899.html