Tarjan缩点+分层图+spfa最长路【洛谷P3119】

传送门:https://www.luogu.org/problemnew/show/P3119

这个题目一眼看上去,有环,我们就直接tarjan缩点。

但是有一条边可以逆着走,很显然的思路就是枚举每条边,记录一个最大值。(我不会写枚举边的暴力)

所以我们来介绍一下另外一种思路,建分层图。

现在我们在缩点之后的DAG上操作。

我们在DAG上建图的时候,用下图的方式建:

Tarjan缩点+分层图+spfa最长路【洛谷P3119】_第1张图片

DAG结点为1,2,3,多加出来的点为4,5,6,我们就把2连到4,3连到5,这样,2到4就相当于2到1,也就是1到2的反边。

具体怎么建的,就是add(from,to),add(to,from+N),add(from+N,to+N);

这样,我们就把分层图给建好啦。

哦对了,权值别忘记更新了,这个题目是点权,没关系,把他当成边权就可以了。

然后在分层图上从1跑spfa最长路,因为最后必须回到1,所以结果就是dis[color[1]+N],因为1号结点对应的是1+N结点。

下面是大家喜闻乐见的代码:

#include 
using namespace std;
const int maxn = 2e5+7;
int low[maxn],dfn[maxn];
vector E[maxn];
vector G[maxn*2];
int color[maxn],sum[maxn*2]; 
int n,m;
int cnt,col;
stack s;
int ins[maxn];
int inq[maxn];
int dis[maxn];
void tarjan(int x)
{
	low[x] = dfn[x] = ++cnt;
	s.push(x);
	ins[x] = 1;
	for(int i=0;i q;
	q.push(s);
	inq[s] = 1;
	while(!q.empty())
	{
		int now = q.front();
		q.pop();
		inq[now] = 0;
		for(int i=0;i>n>>m;
	int x,y;
	for(int i=0;i>x>>y;
		E[x].push_back(y);
	}
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i]) tarjan(i);
	}
	if(col==1)
	{
		cout<

 

你可能感兴趣的:(Tarjan缩点+分层图+spfa最长路【洛谷P3119】)