tarjan缩点/求桥模板

这么一看缩点用tarjan也没必要啊,用之前那个存反向边dfs两次的做法就行了

缩点过程就是遍历边,两侧不同scc就加边

#include<bits/stdc++.h>  
//#pragma comment(linker, "/STACK:1024000000,1024000000")   
#include<stdio.h>  
#include<algorithm>  
#include<queue>  
#include<string.h>  
#include<iostream>  
#include<math.h>  
#include<set>  
#include<map>  
#include<vector>  
#include<iomanip>  
using namespace std;  
#define ll long long  
#define pb push_back  
#define FOR(a) for(int i=1;i<=a;i++) 
#define sqr(a) (a)*(a)

const int maxn=1e6+7;

struct EDGE{
	int from,to,d,nxt;
	bool sign;	//桥
}edge[maxn<<1];
int head[maxn],edgenum;
void add(int u,int v,int d){
	edge[edgenum]=(EDGE){u,v,d,head[u]};head[u]=edgenum++;
}
int DFN[maxn],Low[maxn],Stack[maxn],top,Time;
//Low[u]是u的子树反向弧能指向的最靠近总根的祖先的时间戳
int taj;
int Belong[maxn];	//连通分量所属
bool Instack[maxn];
vector<int>bcc[maxn];

void tarjan(int u,int fa){
	DFN[u]=Low[u]=++Time;
	Stack[top++]=u;
	Instack[u]=1;
	for(int i=head[u];~i;i=edge[i].nxt){
		int v=edge[i].to;
		if(DFN[v]==-1){
			tarjan(v,u);
			Low[u]=min(Low[u],Low[v]);
			if(DFN[u]<Low[v]){		//v上不去
				edge[i].sign=1;
			}
		}else if(Instack[v])Low[u]=min(Low[u],DFN[v]);
	}
	if(Low[u]==DFN[u]){
		int now;
		taj++;bcc[taj].clear();
		do{
			now=Stack[--top];
			Instack[now]=0;
			Belong[now]=taj;
			bcc[taj].pb(now);
		}while(now!=u);
	}
}
void tarjan_init(int all){
	memset(DFN,-1,sizeof DFN);
	memset(Instack,0,sizeof Instack);
	top=Time=taj=0;
	for(int i=1;i<=all;i++)if(DFN[i]==-1)tarjan(i,i);
}
vector<int>G[maxn];
int du[maxn];
void suodian(){
	memset(du,0,sizeof du);
	for(int i=1;i<=taj;i++)G[i].clear();
	for(int i=0;i<edgenum;i++){
		int u=Belong[edge[i].from],v=Belong[edge[i].to];
		if(u!=v){G[u].pb(v);du[v]++;}
	}
}
void init(){memset(head,-1,sizeof head);}


posted @ 2017-12-07 15:39  Drenight  阅读(207)  评论(0编辑  收藏  举报