由于路和银行都可以重复走,而银行里的钱只能被抢走一次,所以考虑到tarjan缩点,之后跑spfa的最长路即可
代码
#include<bits/stdc++.h>
using namespace std;
int n,m,s,p,top,times;
const int maxn=5e5+5;
const int inf=0x3f3f3f3f;
int S,T,dis[maxn],st[maxn],vis[maxn],h[maxn],tot,x[maxn],y[maxn],col_type,col[maxn],sum[maxn],in[maxn],money[maxn],head[maxn],dfn[maxn],low[maxn],cnt;
struct edge
{
int to,nxt;
}G[maxn];
struct edgee
{
int to,nxt,v;
}e[maxn];
void Add(int x,int y, int z)
{
e[++tot].to=y; e[tot].nxt=h[x]; e[tot].v=z; h[x]=tot;
}
int spfa()
{
for(int i=0;i<=n;i++) dis[i]=-inf;
dis[S]=0; vis[S]=1;
queue <int> q; q.push(S);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=h[u];i;i=e[i].nxt)
{
int to=e[i].to;
int v=e[i].v;
if(dis[to]<dis[u]+v)
{
dis[to]=dis[u]+v;
if(!vis[to])
{
vis[to]=1;
q.push(to);
}
}
}
vis[u]=0;
}
return dis[T];
}
void add(int x ,int y)
{
G[++cnt].to=y; G[cnt].nxt=head[x]; head[x]=cnt;
}
void tarjan(int x)
{
low[x]=dfn[x]=++times;
st[++top]=x; in[x]=1;
for(int i=head[x];i;i=G[i].nxt)
{
int to=G[i].to;
if(!dfn[to])
{
tarjan(to);
low[x]=min(low[x],low[to]);
}
else if(in[to]) low[x]=min(low[x],dfn[to]);
}
if(low[x]==dfn[x])
{
col_type++;
while(st[top+1]!=x)
{
sum[col_type]+=money[st[top]];
in[st[top]]=0;
col[st[top--]]=col_type;
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]),add(x[i],y[i]);
for(int i=1;i<=n;i++) scanf("%d",&money[i]);
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
S=0; T=col_type+1; int bar;
scanf("%d%d",&s,&p);
for(int i=1;i<=m;i++) if(col[x[i]]!=col[y[i]]) Add(col[x[i]],col[y[i]],sum[col[y[i]]]);
Add(S,col[s],sum[col[s]]);
for(int i=1;i<=p;i++) scanf("%d",&bar),Add(col[bar],T,0);
printf("%d\n",spfa());
return 0;
}