Problem Specification | Value |
---|---|
Time Limit | 15 Sec |
Memory Limit | 162 MB |
Submit | 2546 |
Solved | 1064 |
Description
Input
第一行包含两个整数 N、M. N 表示路口的个数, M 表示道路条数. 接下来 M 行, 每行两个整数, 这两个整数都在 1 到 N 之间, 第 i+1 行的两个整数表示第 i 条道路的起点和终点的路口编号. 接下来 N 行, 每行一个整数, 按顺序表示每个路口处的 ATM 机中的钱数. 接下来一行包含两个整数 S、P, S 表示市中心的编号, 也就是出发的路口. P 表示酒吧数目. 接下来的一行中有 P 个整数, 表示 P 个有酒吧的路口的编号
Output
输出一个整数, 表示 Banditji 从市中心开始到某个酒吧结束所能抢劫的最多的现金总数.
Sample Input
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
Sample Output
47
HINT
50% 的输入保证 N, M<=3000. 所有的输入保证 N, M<=500000. 每个 ATM 机中可取的钱数为一个非负整数且不超过 4000. 输入数据保证你可以从市中心沿着 Siruseri 的单向的道路到达其中的至少一个酒吧.
Explanation
先强连通分量缩点, 得到一个有向无环图.
然后简单跑一遍 SPFA 就可以了.
很容易 WA~ 并且不停 Presentation Error 233~
Example Code
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <stack>
#include <queue>
#include <cstring>
using namespace std;
typedef long long lli;
const int maxn = 500100, maxm = 500100;
const lli infinit = 0x007f7f7f7f7f7f7fll;
class Graph
{
public:
struct edge
{
int u, v;
edge *next;
};
edge *edges[maxn], epool[maxm];
int n, ecnt;
void addedge(int u, int v)
{
edge *p = &epool[++ecnt];
p->u = u; p->v = v;
p->next = edges[u]; edges[u] = p;
return ;
}
void clear(void)
{
memset(edges, 0, sizeof(edges));
memset(epool, 0, sizeof(epool));
n = ecnt = 0;
return ;
}
};
class Tarjan : public Graph
{
public:
int dfn[maxn], low[maxn];
int belong[maxn]; // This is the result of the final procedure...
int bcnt, dcnt;
stack<int> stk;
bool instk[maxn];
// My greatest gratitude to @byvoid for this article...
// https://www.byvoid.com/blog/scc-tarjan
void dfs(int p)
{
dfn[p] = low[p] = ++dcnt; // Assign DFS number index
stk.push(p);
instk[p] = true;
for (edge *ep = edges[p]; ep; ep = ep->next) {
int q = ep->v;
if (!dfn[q]) {
dfs(q);
if (low[p] > low[q])
low[p] = low[q];
} else if (instk[q] && dfn[q] < low[p])
low[p] = dfn[q];
}
if (dfn[p] == low[p]) {
bcnt++; // Assign new belong / block counter / index
int q = 0;
do {
q = stk.top();
stk.pop();
instk[q] = false;
belong[q] = bcnt;
} while (q != p);
}
return ;
}
void eval(void)
{
while (!stk.empty())
stk.pop();
bcnt = dcnt = 0;
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
for (int i = 1; i <= n; i++)
if (!dfn[i])
dfs(i);
return ;
}
} graph;
class SPFA : public Graph
{
public:
lli dist[maxn];
lli weight[maxn];
bool inque[maxn];
int s;
void eval(void)
{
queue<int> que;
for (int i = 1; i <= n; i++)
inque[i] = false, dist[i] = infinit;
que.push(s);
inque[s] = true;
dist[s] = weight[s];
while (!que.empty()) {
int p = que.front();
que.pop();
for (edge *ep = edges[p]; ep; ep = ep->next) {
if (dist[p] + weight[ep->v] > dist[ep->v] || dist[ep->v] >= infinit) {
dist[ep->v] = dist[p] + weight[ep->v];
if (!inque[ep->v]) {
que.push(ep->v);
inque[ep->v] = true;
}
}
}
inque[p] = false;
}
return ;
}
} spfa;
int n, m, S, P;
int v[maxn];
int pub[maxn], pubcnt;
int main(int argc, char** argv)
{
scanf("%d%d", &n, &m);
graph.n = n;
spfa.n = n;
for (int i = 1, a, b; i <= m; i++) {
scanf("%d%d", &a, &b);
graph.addedge(a, b);
}
for (int i = 1; i <= n; i++)
scanf("%d", &v[i]);
scanf("%d%d", &S, &P);
for (int i = 1, a; i <= P; i++) {
scanf("%d", &a);
pub[++pubcnt] = a;
}
// Done input (That was a lot of input!)
graph.eval();
// Done evaluating graph values, now building new graph for SPFA.
for (int i = 1; i <= m; i++) {
Graph::edge* ed = &graph.epool[i];
int p = graph.belong[ed->u],
q = graph.belong[ed->v];
if (p != q)
spfa.addedge(p, q);
}
for (int i = 1; i <= n; i++)
spfa.weight[graph.belong[i]] += v[i];
spfa.s = graph.belong[S];
spfa.eval();
lli res = 0;
for (int i = 1; i <= pubcnt; i++) {
if (spfa.dist[graph.belong[pub[i]]] < infinit)
res = max(res, spfa.dist[graph.belong[pub[i]]]);
}
printf("%lld", res);
return 0;
}