边双
没有桥的极大连通子图(\(u\) 到 \(v\) 总有两条路径满足无边交),额外处理孤点
void tar(int now){
dfn[now]=low[now]=++dfscnt;
stk[++tp]=now;for(int v:vc[now]) if(v!=lst){
if(!dfn[v]){
tar(v);low[now]=min(low[now],low[v]);
if(low[v]>dfn[now]){
//(now,v)是桥
++kcnt;do bel[stk[tp]].push_back(kcnt);while(stk[tp--]!=v);
}
}
else low[now]=min(low[now],dfn[v]);
}
}
点双
没有割点的极大连通子图(\(u\) 到 \(v\) 总有两条路径满足除 \(u,v\) 两点外无点交),两点一边算作点双,仅割点属于多个,圆方树圆方相间,额外处理孤点
void tar(int now){
dfn[now]=low[now]=++dfscnt;
stk[++tp]=now;for(int v:vc[now]){
if(!dfn[v]){
tar(v);low[now]=min(low[now],low[v]);
if(low[v]>=dfn[now]){
++kcnt;bel[now].push_back(kcnt);
do bel[stk[tp]].push_back(kcnt);while(stk[tp--]!=v);
}
}
else low[now]=min(low[now],dfn[v]);
}
}
仙人掌上树
每个简单环(包括二元环)为点双,两点一边不算点双直接连,方方不相接,每个环抽出一个作为根连向方点,方点连向剩余结点,已经父->子定向,边权具体分析
void tar(int now,int lst){
dfn[now]=low[now]=++dcnt;stk[++tp]=now;
for(auto[v,w]:gp[now]) if(v!=lst){
if(!dfn[v]){
tar(v,now);low[now]=min(low[now],low[v]);
if(low[v]>dfn[now]) vc[now].push_back((ed){v,w});
}
else if(dfn[v]<low[now]){
low[now]=dfn[v];
vc[v].push_back((ed){++fc,0});rt[fc]=v;
for(int t=tp;stk[t]!=v;--t) vc[fc].push_back((ed){stk[t],0});
}
}--tp;
}
强连通分量
void tar(int now){
dfn[now]=low[now]=++dfscnt;
stk[++tp]=now;ist[now]=1;
for(int v:vc[now]){
if(!dfn[v]){
tar(v);low[now]=min(low[now],low[v]);
}
else if(ist[v]) low[now]=min(low[now],dfn[v]);
}
if(dfn[now]==low[now]){
++kcnt;do ist[stk[tp]]=0,bel[stk[tp]]=kcnt;while(stk[tp--]!=now);
}
}
标签:++,tp,stk,dfn,low,now,波特,不会
From: https://www.cnblogs.com/vanspace/p/18337012