1. 程式人生 > >Luogu 3627 [APIO2009]搶掠計劃

Luogu 3627 [APIO2009]搶掠計劃

hid 最長路 set else if val display == empty 什麽

不爽。

為什麽tarjan能爆棧啊

十分顯然的縮點,給縮點之後的點連上權值為後一個點集權值的有向邊,然後spfa跑最長路。

註意一開始$dis_{st}$應該等於$st$這個集合的權值。

時間復雜度$O(能過)$。

非遞歸版的tarjan可以學習一下。

Code:

技術分享圖片
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;

const int N = 8e5 + 5;
const int
inf = 0x3f3f3f3f; int n, m, st, edNum, dfsc = 0, dfn[N], low[N], bel[N]; int tot = 0, head[N], scc = 0, a[N], val[N], dis[N]; int top = 0, sta[N], inx[N << 1], iny[N << 1]; bool vis[N], isEnd[N], sccEnd[N]; stack <int> S; struct Edge { int to, nxt, val; } e[N << 1
]; inline void add(int from, int to, int v = 0) { e[++tot].to = to; e[tot].val = v; e[tot].nxt = head[from]; head[from] = tot; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > 9|| ch < 0; ch = getchar()) if(ch ==
-) op = -1; for(; ch >= 0 && ch <= 9; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline int min(int x, int y) { return x > y ? y : x; } inline void chkMax(int &x, int y) { if(y > x) x = y; } /*void tarjan(int x) { dfn[x] = low[x] = ++dfsc; sta[++top] = x, vis[x] = 1; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(!dfn[y]) tarjan(y), low[x] = min(low[x], low[y]); else if(vis[y]) low[x] = min(low[x], dfn[y]); } if(low[x] == dfn[x]) { ++scc; for(; sta[top + 1] != x; top--) { sccEnd[scc] |= isEnd[sta[top]]; bel[sta[top]] = scc; val[scc] += a[sta[top]]; vis[sta[top]] = 0; } } } */ void tarjan(int fir) { low[fir] = dfn[fir] = ++dfsc; sta[++top] = fir, vis[fir] = 1; S.push(fir); for(; !S.empty(); ) { int x = S.top(); for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(!dfn[y]) { dfn[y] = low[y] = ++dfsc; sta[++top] = y, vis[y] = 1; S.push(y); break; } } if(x == S.top()) { for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(dfn[y] > dfn[x]) low[x] = min(low[x], low[y]); else if(vis[y]) low[x] = min(low[x], dfn[y]); } if(low[x] == dfn[x]) { ++scc; for(; sta[top + 1] != x; top--) { sccEnd[scc] |= isEnd[sta[top]]; bel[sta[top]] = scc; val[scc] += a[sta[top]]; vis[sta[top]] = 0; } } S.pop(); } } } queue <int> Q; void spfa() { memset(dis, 0x3f, sizeof(dis)); dis[st] = -val[st]; Q.push(st); vis[st] = 1; for(; !Q.empty(); ) { int x = Q.front(); Q.pop(); vis[x] = 0; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(dis[y] > dis[x] + e[i].val) { dis[y] = dis[x] + e[i].val; if(!vis[y]) Q.push(y), vis[y] = 1; } } } } int main() { read(n), read(m); for(int x, y, i = 1; i <= m; i++) { read(x), read(y); inx[i] = x, iny[i] = y; add(x, y); } for(int i = 1; i <= n; i++) read(a[i]); read(st), read(edNum); for(int x, i = 1; i <= edNum; i++) read(x), isEnd[x] = 1; for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); /* for(int i = 1; i <= n; i++) printf("%d ", bel[i]); printf("\n"); for(int i = 1; i <= n; i++) printf("%d ", val[i]); printf("\n"); */ tot = 0; memset(head, 0, sizeof(head)); for(int i = 1; i <= m; i++) { if(bel[inx[i]] == bel[iny[i]]) continue; add(bel[inx[i]], bel[iny[i]], -val[bel[iny[i]]]); } st = bel[st]; spfa(); int ans = 0; for(int i = 1; i <= scc; i++) if(sccEnd[i] && dis[i] != inf) chkMax(ans, -dis[i]); printf("%d\n", ans); return 0; }
View Code

Luogu 3627 [APIO2009]搶掠計劃