[BZOJ1179][Apio2009]Atm
试题描述
输入
第一行包含两个整数N、M。N表示路口的个数,M表示道路条数。接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号。接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数。接下来一行包含两个整数S、P,S表示市中心的编号,也就是出发的路口。P表示酒吧数目。接下来的一行中有P个整数,表示P个有酒吧的路口的编号
输出
输出一个整数,表示Banditji从市中心开始到某个酒吧结束所能抢劫的最多的现金总数。
输入示例
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
输出示例
47
数据规模及约定
50%的输入保证N, M<=3000。所有的输入保证N, M<=500000。每个ATM机中可取的钱数为一个非负整数且不超过4000。输入数据保证你可以从市中心沿着Siruseri的单向的道路到达其中的至少一个酒吧。
题解
强连通分量缩点再DP就行了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
#include <queue>
#include <cstdlib>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 500010
#define maxm 500010
int n, m[3], S, head[3][maxn], next[3][maxm], to[3][maxm], val[maxn], f[maxn];
bool has[maxn], sh[maxn];
void AddEdge(int a, int b) {
to[0][++m[0]] = b; next[0][m[0]] = head[0][a]; head[0][a] = m[0];
swap(a, b);
to[1][++m[1]] = b; next[1][m[1]] = head[1][a]; head[1][a] = m[1];
return ;
}
void AddEdge2(int a, int b) {
to[2][++m[2]] = b; next[2][m[2]] = head[2][a]; head[2][a] = m[2];
return ;
}
int cnt, outs[maxn];
bool vis[maxn];
void dfs1(int u) {
if(vis[u]) return ; vis[u] = 1;
for(int e = head[0][u]; e; e = next[0][e]) if(!vis[to[0][e]]) dfs1(to[0][e]);
outs[++cnt] = u;
return ;
}
int scc, sccno[maxn], sccv[maxn];
void dfs2(int u) {
if(vis[u]) return ; vis[u] = 1;
sccno[u] = scc; sccv[scc] += val[u];
for(int e = head[1][u]; e; e = next[1][e]) if(!vis[to[1][e]]) dfs2(to[1][e]);
return ;
}
int main() {
n = read(); int m = read();
while(m--) {
int a = read(), b = read();
AddEdge(a, b);
}
for(int i = 1; i <= n; i++) val[i] = read();
S = read();
int cb = read(); for(int i = 1; i <= cb; i++) has[read()] = 1;
for(int i = 1; i <= n; i++) dfs1(i);
memset(vis, 0, sizeof(vis));
for(int i = n; i; i--) scc++, dfs2(outs[i]);
for(int i = 1; i <= n; i++) {
for(int e = head[0][i]; e; e = next[0][e]) if(sccno[i] != sccno[to[0][e]])
AddEdge2(sccno[i], sccno[to[0][e]]);
sh[sccno[i]] |= has[i];
}
f[sccno[S]] = sccv[sccno[S]];
for(int i = sccno[S]; i <= scc; i++)
for(int e = head[2][i]; e; e = next[2][e]) f[to[2][e]] = max(f[to[2][e]], f[i] + sccv[to[2][e]]);
int ans = 0;
for(int i = sccno[S]; i <= scc; i++) if(sh[i]) ans = max(ans, f[i]);
printf("%d\n", ans);
return 0;
}