模板 缩点

点我飞去luogu

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;

int n,m;
int value[10001],sum[10001];
struct way
{
	int x;
	int y;
}b[100001];//把边存好,需要建两次图

vector <int> map[10001];
int dfn[10001],low[10001];//tarjan用
int stack[10001],top,inx;//手写栈
int color[10001],tot;//染色,tot为总颜色数
bool vis[10001];
void tarjan(int x)//强联通染色
{
	stack[++top]=x;
	dfn[x]=low[x]=++inx;
	vis[x]=1;
	for(unsigned int i=0;i<map[x].size();i++)
	{	
		int v=map[x][i];
		if(!dfn[v])
			tarjan(map[x][i]),
			low[x]=min(low[x],low[v]);
		else if(vis[v])
			low[x]=min(low[x],dfn[v]);
	}
	if(low[x]==dfn[x])
	{
		tot++;
		while(stack[top+1]!=x)
			color[stack[top]]=tot,
			sum[tot]+=value[stack[top]],
			vis[stack[top--]]=0;
	}
}

int f[10001];//各点开始dfs的点权值和
int ans;
void dfs(int x)//x=color
{
	if(f[x])
		return ;
	f[x]=sum[x];
	int maxv=0;
	for(unsigned int i=0;i<map[x].size();i++)
	{	
		int v=map[x][i];
		if(!f[v])
			dfs(v);
		maxv=max(maxv,f[v]);//压行选手(我)注意,这里如果和上一句用','连在一起会少更新那些已经访问的颜色
	}
	f[x]+=maxv;
}

int main()
{
	in(n);in(m);
	for(int i=1;i<=n;i++)
		in(value[i]);
	
	for(int i=0;i<m;i++)
	{
		int u,v;
		in(u);in(v);
		b[i]=(way){u,v};
		map[u].push_back(v);//tarjan建图
	}
	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);
	
	for(int i=1;i<=n;i++)
		map[i].clear();
	for(int i=0;i<m;i++)
		if(color[b[i].x]!=color[b[i].y])
			map[color[b[i].x]].push_back(color[b[i].y]);//枚举边,两端不同色才需要颜色之间的连边
	for(int i=1;i<=tot;i++)
		if(!f[i])
			dfs(i),ans=max(ans,f[i]);
	
	cout<<ans;
	return 0;
}
原文地址:https://www.cnblogs.com/syhien/p/7784058.html