传送门:https://www.luogu.org/problemnew/show/P3119
这个题目一眼看上去,有环,我们就直接tarjan缩点。
但是有一条边可以逆着走,很显然的思路就是枚举每条边,记录一个最大值。(我不会写枚举边的暴力)
所以我们来介绍一下另外一种思路,建分层图。
现在我们在缩点之后的DAG上操作。
我们在DAG上建图的时候,用下图的方式建:
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<