SP14887 GOODA - Good Travels 题解

题目传送门

前置知识

Tarjan 算法 | 最短路

解法

缩点后原图就成为了一个有向无环图,此时每个点最多被经过一次,故在求最长路的过程中可以将点权和边权混着转移。

  • 上篇题解用拓扑实现查找两点间最长路的做法正确性不会证,遂写了份 Dijkstra 求最长路。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
struct node
{
	ll nxt,to;
}e[1000010];
stack<ll>s;
ll head[1000010],dfn[1000010],low[1000010],ins[1000010],c[1000010],a[1000010],b[1000010],u[1000010],v[1000010],vis[1000010],dis[1000010],cnt=0,tot=0,ans=0;
void add(ll u,ll v)
{
	cnt++;
	e[cnt].nxt=head[u];
	e[cnt].to=v;
	head[u]=cnt;
}
void tarjan(ll x)
{
	ll k=0,i;
	tot++;
	dfn[x]=low[x]=tot;
	ins[x]=1;
	s.push(x);
	for(i=head[x];i!=0;i=e[i].nxt)
	{
		if(dfn[e[i].to]==0)
		{
			tarjan(e[i].to);
			low[x]=min(low[x],low[e[i].to]);
		}
		else
		{
			if(ins[e[i].to]==1)
			{
				low[x]=min(low[x],dfn[e[i].to]);
			}
		}
	}
	if(dfn[x]==low[x])
	{
		ans++;
		while(x!=k)
		{
			k=s.top();
			ins[k]=0;
			c[k]=ans;
			b[ans]+=a[k];
			s.pop();
		}
	}
}
void dijkstra(ll st)
{
	ll x,i;
	memset(vis,0,sizeof(vis));
	memset(dis,-0x3f,sizeof(dis));
	priority_queue<pair<ll,ll> >q;
	dis[st]=b[st];
	q.push(make_pair(dis[st],st));
	while(q.empty()==0)
	{
		x=q.top().second;
		q.pop();
		if(vis[x]==0)
		{
			vis[x]=1;
			for(i=head[x];i!=0;i=e[i].nxt)
			{
				if(dis[e[i].to]<dis[x]+b[e[i].to])
				{
					dis[e[i].to]=dis[x]+b[e[i].to];
					q.push(make_pair(dis[e[i].to],e[i].to));
				}
			}
		}
	}
}
int main()
{
	ll n,m,st,ed,i;
	cin>>n>>m>>st>>ed;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(i=1;i<=m;i++)
	{
		cin>>u[i]>>v[i];
		add(u[i],v[i]);
	}
	for(i=1;i<=n;i++)
	{
		if(dfn[i]==0)
		{
			tarjan(i);
		}
	}
	cnt=0;
	memset(e,0,sizeof(e));
	memset(head,0,sizeof(head));
	for(i=1;i<=m;i++)
	{
		if(c[u[i]]!=c[v[i]])
		{
			add(c[u[i]],c[v[i]]);
		}
	}
	dijkstra(c[st]);
	cout<<dis[c[ed]]<<endl;
	return 0;
}
posted @ 2024-07-14 11:25  hzoi_Shadow  阅读(4)  评论(0编辑  收藏  举报
扩大
缩小