[BZOJ1179][Apio2009]Atm
[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; }