Luogu 3627 [APIO2009]抢掠计划
不爽。
为什么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; }