点击这里查看原题
先缩点,然后把负的点权当做边权,用SPFA求最短路(取反即为最长路),在所有有酒吧的点中取dis最大的点即为答案
/*
User:Small
Language:C++
Problem No.:1179
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=5e5+5;
int n,m,c[M],s,p,dis[M],f[M],C[M],fir[M],FIR[M],tot,dfn[M],low[M],cnt,ans;
bool vis[M],is_end[M];
stack<int> ss;
struct edge{
int v,nex;
}e[M],E[M];
void add(int u,int v,int i){
e[i]=(edge){v,fir[u]};
fir[u]=i;
}
void Add(int u,int v){
E[++tot]=(edge){v,FIR[u]};
FIR[u]=tot;
}
void dfs(int u){
dfn[u]=low[u]=++tot;
ss.push(u);
vis[u]=1;
for(int i=fir[u];i;i=e[i].nex){
int v=e[i].v;
if(!dfn[v]){
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
cnt++;
while(1){
int q=ss.top();
ss.pop();
vis[q]=0;
f[q]=cnt;
C[cnt]+=c[q];
if(q==u) break;
}
}
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v,i);
}
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
scanf("%d%d",&s,&p);
for(int i=1;i<=p;i++){
int x;
scanf("%d",&x);
is_end[x]=1;
}
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i);
tot=0;
for(int i=1;i<=n;i++){
for(int j=fir[i];j;j=e[j].nex){
int v=e[j].v;
if(f[i]!=f[v]) Add(f[i],f[v]);
}
}
memset(dis,63,sizeof(dis));
queue<int> q;
q.push(f[s]);
vis[f[s]]=1;
dis[f[s]]=-C[f[s]];
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=FIR[u];i;i=E[i].nex){
int v=E[i].v;
if(dis[v]>dis[u]-C[v]){
dis[v]=dis[u]-C[v];
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
for(int i=1;i<=n;i++) if(is_end[i]) ans=max(ans,-dis[f[i]]);
printf("%d\n",ans);
return 0;
}