强连通
void tarjan(int u){
dfn[u] = low[u] = ++tim;
vis[u] = 1;
sta.push(u);
for(int i = head[u]; ~i; i = edge[i].next){
int& v = edge[i].to;
if(!dfn[v]){
tarjan(v);
}
if(vis[v]==1){
low[u] = min(low[u],low[v]);
}
}
if(dfn[u] == low[u]){
while(!sta.empty()){
int v = sta.top();
sta.pop();
vis[v] = 2;
ans[num] += val[v];
pos[v] = num;
if(u==v)break;
}
++num;
}
}
求有多少割点?
//cnt 为割点的个数
//root 为根
//ans 为删除该割点后连通图个数.
//若割点为root,则输出ans[root],否则,输出ans[]+1;
void tarjan(int u,int pre)
{
dfn[u] = low[u] = ++tim;
int k = 0;
for(int i = head[u]; ~i; i = edge[i].next)
{
const int& v = edge[i].to;
if(v == pre) continue;
if(!dfn[v])
{
++k;
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(u == root && k > 1){
flag[u] = 1;
ans[u] = k;
}
if(u != root && low[v] >= dfn[u]){
flag[u] = 1;
ans[u]++;
}
}
else low[u] = min(low[u],dfn[v]);
}
cnt += flag[u];
}
求边连通分量
pos代表属于哪一个边连通分量
bridge代表桥
void tarjan(int u,int fa){
dfn[u] = low[u] = ++tim;
sta[tp++] = u;
for(int i = head[u];~i;i=edge[i].next){
int v = edge[i].to;
if(v == fa)continue;
if(!dfn[v]){
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] > dfn[u]){
bridge[++bridgeNum]={u,v};
}
}
else if(dfn[v] < dfn[u]){
low[u] = min(low[u],dfn[v]);
}
}
if(dfn[u] == low[u]){
++num;
int v;
do{
v = sta[--tp];
pos[v] = num;
}while(v != u);
}
}
点双连通分量
void tarjan(int u,int father){
dfn[u] = low[u] = ++time;
for(int i=head[u]; ~i; i=edge[i].next){
int v = edge[i].to;
if(!dfn[v]){
sta.push(u);//存点
tarjan(v,u);
low[u] = min(low[u],low[v]);
if(low[v] >= dfn[u]){
++num;
while(!sta.empty()){
int j = sta.top();
sta.pop();
vec[num].push_back(j);//存的点
if(j == u)break;
}
}
}
else if(dfn[v] < dfn[u]){
sta.push(u);
low[u] = min(low[u],dfn[v]);
}
}
}