tarjan 各类板子集合

tarjan大板子(非讲解):

1、普通缩点DGA

void tarjan(int x){
	dfn[x]=low[x]=++cntp;
	q.push(x);v[x]=1; 
	for(int i=head[x];i;i=bi[i].next){
		int j=bi[i].to;
		if(!dfn[j]){
			tarjan(j);
			low[x]=min(low[x],low[j]);
		}
		else if(v[j])low[x]=min(low[x],dfn[j]);
	}
	if(low[x]==dfn[x]){
		int p;
		num++;//缩点的个数 
		do{
			p=q.top();
			q.pop();
			zh[p]=num;//zh[i]表示 i对应的缩点之后的点 
			cntt[num]++;//cntt[i]表示缩点之后i点代表的点的个数 
			v[p]=0;
		}while(x!=p);
	}
}
//重建边 很多题需要缩点重建边成一个DGA以后在进行操作
for(int i=1;i<=cnt;i++){
	if(zh[bi[i].fr]!=zh[bi[i].to])ad(zh[bi[i].fr],zh[bi[i].to]);
}

2、求割点

void tarjan(int x,int root){
	dfn[x]=low[x]=++cntp;
	int fl=0;
	for(int i=head[x];i;i=bi[i].next){
		int j=bi[i].to;
		if(!dfn[j]){
			tarjan(j);
			low[x]=min(low[x],low[j]);
			if(low[j]>=dfn[x]){
				fl++;
				if(x!=root||fl>1)ge[x]=1;
			}
		}
		else low[x]=min(low[x],dfn[j]);
	}
}

3、求割边

void tarjan(int x,int id){
	dfn[x]=low[x]=++cntp;
	for(int i=head[x];i!=-1;i=bi[i].next){
		int j=bi[i].to;
		if(!dfn[j]){
			tarjan(j,i);
			low[x]=min(low[x],low[j]);
			if(low[j]>dfn[x])bb[i]=bb[i^1]=1;//注意边要从0或2开始存
		}
		else if(i!=(id^1))low[x]=min(low[x],dfn[j]);
	}
}

4、求边双连通分量

void tarjan(int x,int id){
	dfn[x]=low[x]=++cntp;
	q.push(x);
	for(int i=head[x];i!=-1;i=bi[i].next){
//		cout<<i<<' '<<id<<endl;
		if(i==(id^1))continue;
		int j=bi[i].to;
		if(!dfn[j]){
			tarjan(j,i);
			low[x]=min(low[x],low[j]);
		}
		else low[x]=min(low[x],dfn[j]);
	}
	if(dfn[x]==low[x]){和父亲的边是割边,和栈里在他上面的点在一个边双连通分量里面。
		num++;
		int p;
		do{
			p=q.top();
			q.pop();
			zh[p]=num;
		}while(p!=x);
	}
}

5、点双连通分量

void tarjan(int x){
	dfn[x]=low[x]=++cntp;
	int fl=0;
	for(int i=head[x];i;i=bi[i].next){
		int j=bi[i].to;
		if(!dfn[j]){
			q.push(j);
			tarjan(j);
			low[x]=min(low[x],low[j]);
			if(low[j]>=dfn[x]){
				num++;
				int p;
				do{
					p=q.top();
					q.pop();
					mann[num].ps(p);
				}while(p!=j);
				mann[num].ps(x);
			}
		}
		else low[x]=min(low[x],dfn[j]);
	}
}

END

posted @ 2024-03-13 14:46  lzrG23  阅读(15)  评论(0编辑  收藏  举报