P3627 [APIO2009] 抢掠计划(atm) 题解

分析

显然我们要处理最多的马内的路径,就要跑最长路,那么就可以用spfa跑

但是有环,spfa不能用spfa会似掉

好办,跑一遍tarjan干掉环,spfa就又活了

停下的酒馆也好处理,直接遍历找求max

数组功能介绍

const int maxn=1000010;
int n,m,s,p;
int dis[maxn];// 跑spfa用
int h[maxn],to[maxn],nxt[maxn],w[maxn],tot,cnt,num;// 前向星用,w存一开始的点权
int h1[maxn],to1[maxn],nxt1[maxn],tot1,w1[maxn],w2[maxn];// 缩点后的存储
int zhan[maxn],top,in_zhan[maxn];//栈及元素是否在栈判断
int dfn[maxn],low[maxn],c[maxn];// tarjan用
bool v[maxn],bar[maxn],bar1[maxn];// v是跑spfa用的,bar就是原酒馆,bar1是缩点后的
int ans;
vector<int> scc[maxn];// tarjan的

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000010;
int n,m,s,p;
int dis[maxn];
int h[maxn],to[maxn],nxt[maxn],w[maxn],tot,cnt,num;
int h1[maxn],to1[maxn],nxt1[maxn],tot1,w1[maxn],w2[maxn];
int zhan[maxn],top,in_zhan[maxn];
int dfn[maxn],low[maxn],c[maxn];
bool v[maxn],bar[maxn],bar1[maxn];
int ans;
vector<int> scc[maxn];

void add(int x,int y)
{
	tot++;
	to[tot]=y;
	nxt[tot]=h[x];
	h[x]=tot;
}
void add1(int x,int y,int z)
{
	tot1++;
	to1[tot1]=y;
	nxt1[tot1]=h1[x];
	w2[tot1]=z;
	h1[x]=tot1;
}
void tarjan(int x)
{
	int y=0;
	num++;
	dfn[x]=low[x]=num;
	zhan[++top]=x;
	in_zhan[x]=true;
	for (int i=h[x];i;i=nxt[i])
	{
		y=to[i];
		if (!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if (in_zhan[y])
		{
			low[x]=min(low[x],dfn[y]);
		}
	}
	if (dfn[x] == low[x])
	{
		cnt++;
		do
		{
			y=zhan[top];
			top--;
			in_zhan[y]=false;
			c[y]=cnt;
			scc[cnt].push_back(y);
			w1[cnt]+=w[y];
			if (bar[y]) bar1[cnt]=true;
		} while (x!=y);
	}
}
void spfa_long(int x)
{
	queue<int> q;
	memset(dis,0,sizeof(dis));// 注意初始化
	dis[x]=w1[x];
	q.push(x);
	v[x] = true;
	while (q.size())
	{
		x=q.front();
		q.pop();
		v[x]=false;
		for (int i=h1[x];i;i=nxt1[i])
		{
			int y=to1[i];
			if (dis[y]<dis[x]+w2[i])// 注意
			{
				dis[y]=dis[x]+w2[i];
				if (!v[y]) q.push(y);
			}
		}
	}
}
int main()
{
	cin >> n >> m;
	int x,y;
	for (int i=1;i<=m;i++)
	{
		cin >> x >> y;
		add(x,y);
	}
	for (int i=1;i<=n;i++) cin >> w[i];
	cin >> s >> p;
	for (int i=1;i<=p;i++)
	{
		cin >> x;
		bar[x]=true;
	}
	for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i);
	for (int i=1;i<=n;i++)
	{
		for (int j=h[i];j;j=nxt[j])
		{
			int y=to[j];
			if (c[i] == c[y]) continue;
			add1(c[i],c[y],w1[c[y]]);
		}
	}
	spfa_long(c[s]);
	for (int i=1;i<=cnt;i++)
	{
		if (bar1[i]) ans = max(ans,dis[i]);
	}
	cout << ans << endl;
	return 0;
}
posted @ 2026-03-22 09:24  msjing  阅读(10)  评论(0)    收藏  举报