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