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);}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章