wa了#3 94pots 求各位大佬帮我康康Orz
思路就是tarjan + 拓扑
缩点后新建从酒馆指向市中心的图
然后就是从酒馆开始拓扑
大概就是酱紫
/*
No ACCEPT
No ACCEPT
No ACCEPT
*/
#include<bits/stdc++.h>
#define long long int
using namespace std;
const int N=5e5+10;
int head[N],to[N],nxt[N],e[N],tot;
int head2[N],to2[N],nxt2[N],tot2;
int n,m,S,P;
int dp[N],anss;//到达dp[i]这个点所能抢劫的最多money
bool bar[N],vis[N],v[N];
int dfn[N],times,low[N],id[N],scc_cnt,scc_size[N];
stack <int> q;
inline int read(){
char ch=getchar();
int ans=0,t=1;
while(ch<'0'||ch>'9'){
if(ch=='-') t=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
ans=ans*10+(ch-'0');
ch=getchar();
}
return ans*t;
}
void add(int x,int y){
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void add2(int x,int y){
to2[++tot2]=y;
nxt2[tot2]=head2[x];
head2[x]=tot2;
}
void tj(int x){
v[x]=true;
dfn[x]=low[x]=++times;
q.push(x);
vis[x]=true;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(!dfn[y]){
tj(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
scc_cnt++;
int tp=0;
do{
tp=q.top();
q.pop();
vis[tp]=false;
id[tp]=scc_cnt;
scc_size[scc_cnt]+=e[tp]; //该缩点中所有ATM的钱
}while(tp!=x);
}
}
void dfs(int x){
dp[x]+=scc_size[x];
int cntt=0;//抢劫的小钱钱
for(int i=head2[x];i;i=nxt2[i]){
int y=to2[i];
if(y==id[S]){
dp[x]+=scc_size[id[S]];//到达市中心
return;
}
if(!dp[y]) dfs(y); //如果算过一个点的就不再计算,直接利用
cntt=max(cntt,dp[y]);
}
dp[x]+=cntt;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=m;i++){
int a,b;
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n;i++) e[i]=read();
cin>>S>>P;
tj(S);
for(int i=1;i<=P;i++){
int x;
cin>>x;
bar[id[x]]=true;
}//酒馆
for(int i=1;i<=n;i++){
if(!id[i]) continue;
for(int j=head[i];j;j=nxt[j]){
int y=to[j];
if(id[y]==id[i]) continue;
add2(id[y],id[i]);
}
}//倒着建图 从酒馆指向终点
for(int i=1;i<=scc_cnt;i++){
if(bar[i]&&!dp[i]) dfs(i);
if(bar[i]) anss=max(anss,dp[i]);
}
cout<<anss;
return 0;
}