【模板】缩点

题目链接

每个强连通分量内部可以自达,可以视为一个点,tarjan跑强连通分量。

重新建边:一条边上的两个点不在一个一个强连通分量里,则将两个强连通分量连边。

可以把原图清空或者重开数组,重开数组的话变量名不要混。

#include<bits/stdc++.h>
using namespace std;
int head[20000],dfn[20000],low[20000],t=0,sta[20000],stac=0,in[20000]
,cnt=0,w[20000],uu[200000],vv[200000],f[20000],color[20000],colornum=0,sum[20000];//u,v是存边,,要开大一点 
struct node{
	int to,nxt;
}road[200000];
void build(int u,int v)
{
	road[++cnt].to=v;
	road[cnt].nxt=head[u];
	head[u]=cnt;
}
void tarjan(int u)
{
	dfn[u]=low[u]=++t;
	in[u]=1;sta[++stac]=u;
	for(int i=head[u];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(!dfn[v]) 
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(in[v]) low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		color[u]=++colornum;
		sum[colornum]=w[u];
		in[u]=0;
		while(sta[stac]!=u)
		{
			color[sta[stac]]=colornum;
			sum[colornum]+=w[sta[stac]];
			in[sta[stac]]=0;
			stac--;//QAQ
		}
		stac--;
	}
}
void dfs(int u)
{
	for(int i=head[u];i;i=road[i].nxt)
	{
		int v=road[i].to;
		if(!f[v]) dfs(v);
		f[u]=max(f[u],f[v]);//儿子不能回到父亲再去下一个儿子 
	}
	f[u]+=sum[u];
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>w[i];
	for(int i=1;i<=m;i++)
	{
		cin>>uu[i]>>vv[i];
		build(uu[i],vv[i]);
	 } 
	for(int i=1;i<=n;i++) 
	{
		if(!dfn[i])
		tarjan(i);
	}
	memset(head,0,sizeof(head));
	cnt=0;
	for(int i=1;i<=m;i++)
		if(color[uu[i]]!=color[vv[i]]) build(color[uu[i]],color[vv[i]]);
	int ans=0;
	for(int i=1;i<=colornum;i++)
	{
		if(!f[i]) dfs(i);
		ans=max(ans,f[i]);
	}
	cout<<ans;
	return 0;
}
posted @ 2020-09-06 08:34  zlq,  阅读(231)  评论(0编辑  收藏  举报