洛谷3672 [APIO2009]搶掠計劃
阿新 • • 發佈:2018-11-12
原題連結
在一個強連通分量裡的\(ATM\)機顯然都可被搶,所以先用\(tarjan\)找強連通分量並縮點,在縮點的後的\(DAG\)上跑最長路,然後掃一遍酒吧記錄答案即可。
#include<cstdio> using namespace std; const int N = 5e5 + 10; struct eg{ int x, y; }; eg a[N]; int fi[N], di[N], ne[N], cfi[N], cdi[N], cne[N], va[N], sta[N], dis[N], dfn[N], low[N], bl[N], bar[N], ru[N], q[N], su[N], l, lc, ti, tp, st, SCC; bool v[N]; inline int re() { int x = 0; char c = getchar(); bool p = 0; for (; c < '0' || c > '9'; c = getchar()) p |= c == '-'; for (; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0'; return p ? -x : x; } inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; } inline void add_c(int x, int y) { cdi[++lc] = y; cne[lc] = cfi[x]; cfi[x] = lc; } inline int minn(int x, int y) { return x < y ? x : y; } inline int maxn(int x, int y) { return x > y ? x : y; } void tarjan(int x) { int i, y; dfn[x] = low[x] = ++ti; sta[++tp] = x; v[x] = 1; for (i = fi[x]; i; i = ne[i]) if (!dfn[y = di[i]]) { tarjan(y); low[x] = minn(low[x], low[y]); } else if (v[y]) low[x] = minn(low[x], dfn[y]); if (!(dfn[x] ^ low[x])) { SCC++; do { y = sta[tp--]; bl[y] = SCC; su[SCC] += va[y]; v[y] = 0; } while (x ^ y); } } void spfa() { int i, x, y, head = 0, tail = 1; q[1] = bl[st]; dis[bl[st]] = su[bl[st]]; while (head ^ tail) { x = q[++head]; v[x] = 0; for (i = cfi[x]; i; i = cne[i]) { y = cdi[i]; if (dis[y] < dis[x] + su[y]) { dis[y] = dis[x] + su[y]; if (!v[y]) { q[++tail] = y; v[y] = 1; } } } } } int main() { int i, k, n, m, x, y, ma = 0; n = re(); m = re(); for (i = 1; i <= m; i++) { a[i].x = re(); a[i].y = re(); add(a[i].x, a[i].y); } for (i = 1; i <= n; i++) va[i] = re(); st = re(); k = re(); for (i = 1; i <= k; i++) bar[i] = re(); for (i = 1; i <= n; i++) if (!dfn[i]) tarjan(i); for (i = 1; i <= m; i++) { x = bl[a[i].x]; y = bl[a[i].y]; if (x ^ y) { add_c(x, y); ru[y]++; } } spfa(); for (i = 1; i <= k; i++) ma = maxn(ma, dis[bl[bar[i]]]); printf("%d", ma); return 0; }