思路
1.先缩点,求出每个强连通分量的金钱数
2.然后建立缩点后的关系以及权值,跑一个模板最长路(路径取反,跑dijkstra(没有环)或者spfa)。
AC代码
/**
缩点 + spfa走最长路
*/
#include<cstdio>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef pair<int, int> pii;
#define IOS ios::sync_with_stdio(false)
const int maxn = 500050;
const int inf = 0x3f3f3f3f;
struct node{
int to, w;
};
int dfn[maxn], low[maxn], color[maxn], sum[maxn], tot, ind = 1;
int from[maxn], to[maxn], cost[maxn], dis[maxn];
bool instack[maxn], vis[maxn];
stack<int> st;
vector<int> G[maxn]; // 记录tarjan
vector<node> G1[maxn]; // 记录spfa
void tarjan(int u){
dfn[u] = low[u] = ind++;
st.push(u);
instack[u] = true;
for (int v : G[u]){
if (!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (instack[v]){
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u]){
int now;
tot++;
do{
now = st.top(); st.pop();
instack[now] = false;
color[now] = tot;
sum[tot] += cost[now];
}while (now != u);
}
}
void spfa(int st){
queue<int> q;
for (int i = 1; i <= tot; ++i) dis[i] = inf;
st = color[st];
q.push(st);
dis[st] = -sum[st];
while (!q.empty()){
int u = q.front(); q.pop();
vis[u] = false;
for (auto i : G1[u]){
int v = i.to;
if (dis[v] > dis[u] + i.w){
dis[v] = dis[u] + i.w;
if (!vis[v]){
vis[v] = true;
q.push(v);
}
}
}
}
}
void solve(){
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i){
scanf("%d%d", &from[i], &to[i]);
G[from[i]].push_back(to[i]);
}
for (int i = 1; i <= n; ++i) scanf("%d", &cost[i]);
for (int i = 1; i <= n; ++i){
if (!dfn[i]){
tarjan(i);
}
}
for (int i = 1; i <= m; ++i){
if(color[from[i]] != color[to[i]]){
G1[color[from[i]]].push_back(node{color[to[i]], -sum[color[to[i]]]});
}
}
int p, x, st;
scanf("%d%d", &st, &p);
spfa(st);
int ans = 0;
while (p--){
scanf("%d", &x);
if (ans < -dis[color[x]]){
ans = -dis[color[x]];
}
}
printf("%d\n", ans);
}
int main(){
solve();
return 0;
}