分析:如果题目中没有环的话就是一道裸的最长路的题目,一旦有环每个城市就会被救多次火了。把有向有环图变成有向无环图只需要tarjan一边就可以了.
#include <bits/stdc++.h> using namespace std; const int maxn = 500010; int n,m,head[maxn],nextt[maxn],to[maxn],tot = 1,a[maxn],S,P,p[maxn],v[maxn],vis[maxn]; int scc[maxn],low[maxn],pre[maxn],cnt,dfs_clock,st,head2[maxn],to2[maxn],nextt2[maxn],tot2 = 1; bool flag[maxn]; long long ans,d[maxn]; stack <int> s; void add(int x,int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void add2(int x,int y) { to2[tot2] = y; nextt2[tot2] = head2[x]; head2[x] = tot2++; } void tarjan(int u) { s.push(u); pre[u] = low[u] = ++dfs_clock; for (int i = head[u];i;i = nextt[i]) { int v = to[i]; if (!pre[v]) { tarjan(v); low[u] = min(low[u],low[v]); } else if (!scc[v]) low[u] = min(low[u],pre[v]); } if (pre[u] == low[u]) { cnt++; while (1) { int t = s.top(); s.pop(); v[cnt] += a[t]; if (t == S) st = cnt; if (p[t]) flag[cnt] = 1; scc[t] = cnt; if (t == u) return; } } } void bfs() { queue <int> q; q.push(st); vis[st] = 1; memset(d,-1,sizeof(d)); d[st] = v[st]; while (!q.empty()) { int u = q.front(); vis[u]--; q.pop(); for (int i = head2[u];i;i = nextt2[i]) { int v2 = to2[i]; if (d[v2] < d[u] + v[v2]) { d[v2] = d[u] + v[v2]; if (!vis[v2]) { vis[v2] = 1; q.push(v2); } } } } } int main() { freopen("save.in","r",stdin); freopen("save.out","w",stdout); scanf("%d%d",&n,&m); for (int i = 1; i <= m; i++) { int x,y; scanf("%d%d",&x,&y); if (x != y) add(x,y); } for (int i = 1; i <= n; i++) scanf("%d",&a[i]); scanf("%d%d",&S,&P); for (int i = 1; i <= P; i++) { int t; scanf("%d",&t); p[t] = 1; } for (int i = 1; i <= n; i++) if (!scc[i]) tarjan(i); for (int i = 1; i <= n; i++) { for (int j = head[i];j;j = nextt[j]) { int v = to[j]; if (scc[i] != scc[v]) add2(scc[i],scc[v]); } } bfs(); for (int i = 1; i <= cnt; i++) if (flag[i]) ans = max(ans,d[i]); cout << ans << endl; return 0; }