##有向图强连通缩点
####所需数组
i d x , l o w [ M A X N ] , d f n [ M A X N ] idx,low[MAXN],dfn[MAXN] idx,low[MAXN],dfn[MAXN]------------时间戳和两个访问标志
s c c n o , s c c [ M A X N ] sccno ,scc[MAXN] sccno,scc[MAXN] ————点属于哪个连通分支,及连通分量数量
s t a c k < i n t > s t , i n s t [ M A X N ] stack<int> st ,inst[MAXN] stack<int>st,inst[MAXN]————栈,一个中间工具,用于分辨点属于哪个连通分量
v e c t o r < i n t > G [ M A X N ] ; vector<int> G[MAXN]; vector<int>G[MAXN];————图
const int N = 40000;
const int M = 500000;
int head[N];
int top;
int n,m;
struct Edge
{
int val;
int to;
int next;
}edge[M];
void addedge(int a,int b,int c)
{
edge[top].to=b;
edge[top].val=c;
edge[top].next=head[a];
head[a]=top++;
}
void init()
{
top=0;
for (int i=1;i<=n;i++) head[i]=-1;
}
int idx,low[N],dfn[N];
int sccno,scc[N];
stack<int>st; int inst[N];
void tarjan_init(){
init();
clr(dfn,0);
clr(inst,0);
clr(scc,0);
sccno=idx=0;
while(!st.empty()) st.pop();
}
void tarjan(int x)
{
low[x]=dfn[x]=++idx;
st.push(x);
inst[x]=1;
for(int i=head[x];~i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v]){
tarjan(v);
low[x]=min(low[v],low[x]);
}
else if(inst[v]){
low[x]=min(low[x],dfn[v]);
}
}
if(low[x]==dfn[x]){
++sccno;
int v;
while(1){
v=st.top();
st.pop();
inst[v]=0;
scc[v] = sccno;
if(x==v) break;
}
}
}
##割边&&割点
//割点
const int N = 40000;
const int M = 500000;
int n,m;
int head[N];
int top;
struct Edge{
int val;
int to;
int next;
}edge[M];
void addedge(int a,int b,int c)
{
edge[top].to=b;
edge[top].val=c;
edge[top].next=head[a];
head[a]=top++;
}
void init()
{
top=0;
for (int i=1;i<=n;i++) head[i]=-1;
}
int low[N],dfn[N],idx;
int iscut[N];
int rootson;
void tarjan_init(){
init();
clr(dfn,0);
idx=rootson=0;
clr(iscut,0);
}
void tarjan(int u,int pre,int id){
dfn[u]=low[u]=++idx;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(i==(id^1)) continue;
if(!dfn[v]){
tarjan(v,u,i);
if(u==1) rootson++;
else {
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]) iscut[u]=1;
}
}else{
low[u]= min(low[u],dfn[v]);
}
}
}
if(rootson>1) iscut[1]=1;//调用后 加一句
//割边
const int N = 40000;
const int M = 500000;
int n,m;
int head[N];
int top;
struct Edge{
int val;
int to;
int next;
}edge[M];
void addedge(int a,int b,int c){
edge[top].to=b;
edge[top].val=c;
edge[top].next=head[a];
head[a]=top++;
}
void init()
{
top=0;
clr(head,-1);
}
int low[N],dfn[N],idx;
int fa[N],isbridge[N];
int bridge;
void tarjan_init()
{
init();
clr(dfn,0);
bridge=idx=0;
clr(isbridge,0);
clr(fa,0);
}
void tarjan(int u,int pre,int id){
fa[u]=pre;
low[u]=dfn[u]=++idx;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(i==(id^1)) continue; //......
if(!dfn[v]){
tarjan(v,u,i);
low[u]=min(low[u],low[v]);
if(low[v] > dfn[u]) {
isbridge[v]=1,bridge++;
//cout<<"isbridge"<<endl;
}
}
else if(v!=pre){ //。。。。。
low[u]=min(low[u],dfn[v]);
}
}
}
//注意isbridge数组与fa数组一起用,且若isbridge[i],则i和fa[i]是割边
//重边要不要注意写法
割边割点注意=号