tarjan板子整理

缩点

stack<int>q;
void tarjan(int u)
{
	pre[u]=low[u]=++cnt;
	q.push(u);
	vis[u]=1;
	for(int i=head[u];i;i=nxt[i])
	{
		int y=to[i];
		if(!pre[y])
		{
			tarjan(y);
			low[u]=min(low[u],low[y]);
		}
		else if(vis[y])
		{
			low[u]=min(low[u],pre[y]);
		}
	}
	if(low[u]==pre[u])
	{
		num++;
		int temp;
		do{
			temp=q.top();
			q.pop();
			vis[temp]=0;
			id[temp]=num;//缩出来的点
			sz[num]++;//每一个缩点的大小
		}while(u!=temp);
	}
}

割点

void tarjan(int u)
{
	pre[u]=low[u]=++cnt;
	int now=0;
	for(int i=head[u];i;i=nxt[i])
	{
		int y=to[i];
		if(!pre[y])
		{
			tarjan(y);
			low[u]=min(low[u],low[y]);
			if(low[y]>=pre[u])//如果u的访问时间比y最早返回的点的时间还靠前,那u被割了y一定不连通
			{
				now++;
				if(u!=root||now>1)
					vis[u]=1;//被标记的即割点
			}
		}
		else
			low[u]=min(low[u],pre[y]);
	}
}

割边

void tarjan(int u,int fa)
{
	pre[u]=low[u]=++cnt;
	for(int i=head[u];i;i=nxt[i])
	{
		int y=to[i];
		if(!pre[y])
		{
			tarjan(y,u);
			low[u]=min(low[u],low[y]);
			if(low[y]>pre[u])
			{
				if(u!=root||now>1)
					vis[(u+1)>>1]=1;//无向图存了两条边 
			}
		}
		else if(y!=fa) low[u]=min(low[u],pre[y]);
	}
}

点双连通分量

void tarjan(int u)
{
    low[u]=pre[u]=++tim;
    q.push(u);
    if(u==root&&head[u]==0)
    {
        dcc_cnt++;
        dcc[dcc_cnt].push_back(u);
        return;
    }//根节点特判 
    int cnt=0;
    for(int i=head[u];i;i=nxt[i])
    {
        int j=to[i];
        if(!pre[j])
        {
            tarjan(j);
            low[u]=min(low[u],low[j]);
            if(pre[u]<=low[j])
            {
                cnt++;                 
                if(u!=root||cnt>1)vis[u]=true;
                ++dcc_cnt;//点双个数 
                int temp;
                do{
                    temp=q.top();
                    q.pop();
                    dcc[dcc_cnt].push_back(temp);//每个点双的点 
                }while(temp!=j);
                dcc[dcc_cnt].push_back(u);
            }
        }
        else low[u]=min(low[u],pre[j]);
    }
}
posted @ 2024-03-08 09:19  _君の名は  阅读(24)  评论(0编辑  收藏  举报