Tarjan全家桶

强联通分量及缩点

#include<bits/stdc++.h>
#define re register
#define v e[i].to
using namespace std;
const int lzw=1e4+3;
int n,m,head[lzw],tot,h[lzw],cnt,dfn[lzw],low[lzw],belong[lzw],stk[lzw],top,dfn_clock,scc_cnt,in[lzw];
struct edge{
	int to,next;
}e[lzw*10],ee[lzw*10];
void add(int a,int b){
	e[++tot].to=b;
	e[tot].next=head[a];
	head[a]=tot;
}
void insert(int a,int b){
	ee[++cnt].to=b;
	ee[cnt].next=h[a];
	h[a]=cnt;
}
void tarjan(int u){//强联通分量
	dfn[u]=low[u]=++dfn_clock,stk[++top]=u;
	for(re int i=head[u];i;i=e[i].next){
		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
		else if(!belong[v]) low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u]){
		scc_cnt++;
		while(1){
			int tmp=stk[top--];
			belong[tmp]=scc_cnt;
			if(tmp==u) break;
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(re int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
	}
	for(re int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	for(re int j=1;j<=n;j++){//缩点
		for(re int i=head[j];i;i=e[i].next){
			if(belong[v]==belong[j]) continue;
			insert(belong[j],belong[v]),in[belong[v]]++;
		}
	}
	return 0;
}

割点

\(\large {\color{red} {注意判根!}}\)

void tarjan(int u,int fa){
      dfn[u]=low[u]=++dfn_clock;
	int ch=0;
	for(re int i=head[u];i;i=e[i].next){
		if(!dfn[v]){
			tarjan(v,u),low[u]=min(low[v],low[u]);
			if((!fa&&++ch>1)||(fa&&low[v]>=dfn[u])) cut[u]=1;
		}
		else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
}

点双联通分量

void tarjan(int u,int fa){
	dfn[u]=low[u]=++dfn_clock;
	stk[++top]=u;
	for(re int i=head[u];i;i=e[i].next){
		if(v==fa) continue;
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				bcc_cnt++;
				while(1){
					int tmp=stk[top--];
					all[bcc_cnt].push_back(tmp);
					if(tmp==v) break;
				}
				all[bcc_cnt].push_back(u);
			}
		}else low[u]=min(low[u],dfn[v]);
	}
}

void tarjan(int u,int fa){
	dfn[u]=low[u]=++dfn_clock;
	for(re int i=head[u];i;i=e[i].next){
		if(v==fa) continue;
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u]) e[i].flag=e[i^1].flag=1;
		}else low[u]=min(low[u],dfn[v]);
	}
}

边双联通分量

桥的部分再加上\(DFS\)

void dfs(int u){
	belong[u]=cnt,vis[u]=1;
	for(re int i=head[u];i;i=e[i].next) if((!e[i].flag)&&(!vis[v])) dfs(v);
}
签名: 我将轻轻叹息,叙述这一切, 许多许多年以后: 林子里有两条路,我—— 选择了行人稀少的那一条, 它改变了我的一生。
posted @ 2020-11-05 11:23  DarthVictor  阅读(63)  评论(0编辑  收藏  举报
莫挨老子!