题面

大秦为你打开题目传送门

题目描述

Siruseri 城中的道路都是单向的。不同的道路由路口连接。按照法律的规定,在每个路口都设立了一个 Siruseri 银行的 ATM 取款机。令人奇怪的是,Siruseri 的酒吧也都设在路口,虽然并不是每个路口都设有酒吧。

Banditji 计划实施 Siruseri 有史以来最惊天动地的 ATM 抢劫。他将从市中心出发,沿着单向道路行驶,抢劫所有他途径的 ATM 机,最终他将在一个酒吧庆祝他的胜利。

使用高超的黑客技术,他获知了每个 ATM 机中可以掠取的现金数额。他希望你帮助他计算从市中心出发最后到达某个酒吧时最多能抢劫的现金总数。他可以经过同一路口或道路任意多次。但只要他抢劫过某个 ATM 机后,该 ATM 机里面就不会再有钱了。 例如,假设该城中有 $6$ 个路口,道路的连接情况如下图所示:

市中心在路口 $1$,由一个入口符号 → 来标识,那些有酒吧的路口用双圈来表示。每个 ATM 机中可取的钱数标在了路口的上方。在这个例子中,Banditji 能抢劫的现金总数为 $47$,实施的抢劫路线是:$1-2-4-1-2-3-5$。

输入格式

第一行包含两个整数 $N,M$。$N$ 表示路口的个数,$M$ 表示道路条数。

接下来 $M$ 行,每行两个整数,这两个整数都在 $1$ 到 $N$ 之间,第 $i+1$ 行的两个整数表示第 $i$ 条道路的起点和终点的路口编号。

接下来 $N$ 行,每行一个整数,按顺序表示每个路口处的 ATM 机中的钱数 $a_i$。

接下来一行包含两个整数 $S,P$,$S$ 表示市中心的编号,也就是出发的路口。$P$ 表示酒吧数目。

接下来的一行中有 $P$ 个整数,表示 $P$ 个有酒吧的路口的编号。

输出格式

输出一个整数,表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。

样例 #1

样例输入 #1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
6 7 
1 2
2 3
3 5
2 4
4 1
2 6
6 5
10
12
8
16
1
5
1 4
4 3 5 6

样例输出 #1

1
47

提示

对于 $50\%$ 的数据,保证 $N, M \le 3000$。

对于 $100\%$ 的数据,保证 $N, M \le 5\times 10^5$,$0 \le a_i \le 4000$。保证可以从市中心沿着 Siruseri 的单向的道路到达其中的至少一个酒吧。

思路

这道题目很简单,由于在一个强连通分量的点互相可达,题目没有说不可以走重复的点,也就是说:一个强连通分量的点都是可以取到的,且如果这个强连通分量中有酒吧,这个强连通分量就可以看成一个酒吧

那么就直接 Tarjan 缩点,把每一个强连通分量都看成一个超级点,跑最长路即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef __int128 int128;

namespace FastIO
{
char buf[1 << 20], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
template<typename T> inline T read(T& x) {
x = 0;
int f = 1;
char ch;
while (!isdigit(ch = getchar())) if (ch == '-') f = -1;
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x *= f;
return x;
}
template<typename T, typename... Args> inline void read(T& x, Args &...x_) {
read(x);
read(x_...);
return;
}
inline ll read() {
ll x;
read(x);
return x;
}
};
using namespace FastIO;

const int N = 5e5 + 10;
const int M = 5e5 + 10;

class Graph {
private :
struct Edge {
int to, nt, wt;
Edge() {}
Edge(int to, int nt, int wt) : to(to), nt(nt), wt(wt) {}
}e[M];
int hd[N], cnte;
public :
inline void AddEdge(int u, int v, int w = 0) {
e[++cnte] = Edge(v, hd[u], w);
hd[u] = cnte;
}
inline int head(int u) { return hd[u]; }
inline int nt(int u) { return e[u].nt; }
inline int to(int u) { return e[u].to; }
inline int wt(int u) { return e[u].wt; }
};

int n, m, s, p;
Graph G;
int uid[N], vid[N];
ll g[N];
int r[N];

inline void Input() {
read(n, m);
int u, v;
for(int i = 1; i <= m; i++) {
read(uid[i], vid[i]);
G.AddEdge(uid[i], vid[i]);
}
for(int i = 1; i <= n; i++) {
read(g[i]);
}
read(s, p);
for(int i = 1; i <= p; i++) {
read(r[i]);
}
}

int dfn[N], low[N], cntd;
int cl[N], cntc;
int stk[N], top, instk[N];

ll sum[N];

inline void Tarjan(int u) {
low[u] = dfn[u] = ++cntd;
stk[++top] = u;
instk[u] = 1;
for(int i = G.head(u); i ; i = G.nt(i)) {
int v = G.to(i);
if(!dfn[v]) {
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(!instk[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(low[u] == dfn[u]) {
cntc++;
instk[u] = 0;
cl[u] = cntc;
sum[cntc] += g[u];
while(stk[top] != u) {
instk[stk[top]] = 0;
cl[stk[top]] = cntc;
sum[cntc] += g[stk[top]];
top--;
}
top--;
}
}

Graph DAG;
ll dis[N];
int vis[N];

inline void Dijkstra(int st) {
priority_queue<pair<ll , ll > > q;
dis[st] = sum[st];
q.push(make_pair(dis[st], st));
while(!q.empty()) {
int u = q.top().second; q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = DAG.head(u); i ; i = DAG.nt(i)) {
int v = DAG.to(i);
if(dis[u] + sum[v] > dis[v]) {
dis[v] = dis[u] + sum[v];
q.push(make_pair(dis[v], v));
}
}
}
}

inline void Work() {
for(int i = 1; i <= n; i++) {
if(!dfn[i]) {
Tarjan(i);
}
}
set<pair<int , int > >st;
for(int i = 1; i <= m; i++) {
if(cl[uid[i]] != cl[vid[i]]) {
st.insert(make_pair(cl[uid[i]], cl[vid[i]]));
}
}
for(auto &p : st) {
DAG.AddEdge(p.first, p.second);
}
Dijkstra(cl[s]);
ll ans = 0;
for(int i = 1; i <= p; i++) {
ans = max(ans, dis[cl[r[i]]]);
}
printf("%lld", ans);
}

int main() {
int T = 1;
while(T--) {
Input();
Work();
}
return 0;
}