题意:一个n个点,m条边的有向图,每个点有权值(取款机),其中有一些点是酒吧,给定起点S,求从起点出发到达一个酒吧所能取到的最大权值,注意一个点一条边可以重复经过多次,但每个取款机只能取一次。
思路:1.“有向图”“重复多次”我们可以想到缩点,因为到达一个极大强连通分量时,分量中每个点都可取到
2.缩点后跑最长路,转化为负权SPFA最短路,计算出dist数组
3.最后对于每个酒吧的dist取最大值即为答案
细节:1.缩点的写法
2.重建图后注意belong数组
3.点权化边权,每条有向边(u,v)的权值为终点v的权值,因此一开始dist[belong[s]]的值不是0,而是其自身所在强连通分量的大小
code:
#include<bits/stdc++.h>
using namespace std;
const int inf=0x7fffffff;
const int maxn=500005;
queue<int>q;
int stak[maxn],top=0;
int n,m,S,P,ans=0;
int from[maxn],head[maxn],Next[maxn],to[maxn],val[maxn],tot=0;
int Head[maxn],Nxt[maxn],To[maxn],w[maxn],tot2=0;
int belong[maxn],dfn[maxn],low[maxn],size[maxn],cls=0,cnt=0;
int dist[maxn];
bool ins[maxn],vis[maxn];
void add(int x,int y){
from[++tot]=x; to[tot]=y; Next[tot]=head[x]; head[x]=tot;
}
void add2(int x,int y,int z){
To[++tot2]=y; Nxt[tot2]=Head[x]; Head[x]=tot2; w[tot2]=z;
}
int read(){
int x=0,f=1; char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
void tarjan(int x){
stak[++top]=x; ins[x]=1;
dfn[x]=low[x]=++cls;
for(int i=head[x];i;i=Next[i]){
int y=to[i];
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}
else if(ins[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
cnt++;
int y;
do{
y=stak[top--];
ins[y]=0;
belong[y]=cnt;
size[cnt]+=val[y];
}while(x!=y);
}
}
void spfa(){
for(int i=1;i<=cnt;i++) dist[i]=inf;
q.push(belong[S]);
dist[belong[S]]=-size[belong[S]];
vis[belong[S]]=1;
while(!q.empty()){
int x=q.front(); q.pop();
vis[x]=0;
for(int i=Head[x];i;i=Nxt[i]){
int y=To[i];
if(dist[x]+w[i]<dist[y]){
dist[y]=dist[x]+w[i];
if(!vis[y]){
vis[y]=1;
q.push(y);
}
}
}
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int x=read(),y=read();
add(x,y);
}
for(int i=1;i<=n;i++) val[i]=read();
for(int i=1;i<=n;i++){ //缩点
if(!dfn[i]) tarjan(i);
}
for(int i=1;i<=m;i++){ //重建图
if(belong[from[i]]!=belong[to[i]]){
add2(belong[from[i]],belong[to[i]],-size[belong[to[i]]]);
}
}
S=read(); P=read();
spfa(); //最短路
for(int i=1;i<=P;i++){
int x=read();
ans=max(ans,-dist[belong[x]]);
}
printf("%d\n",ans);
return 0;
}