【APIO2009】抢掠计划(缩点+最长路)


题目链接:https://loj.ac/problem/10096

做法

这题水到我都不想说什么了,反正就是缩完点然后直接上LPFA(你们管她叫SPFA吗?)求最长路。完。

#include 
#include 
#include 
#include 
#define Re register
using namespace std;
const int maxN = 500005;
int N, M, S, P;
struct EE {
    int u, v;
} E[maxN];
struct Edge {
    int nxt, to;
} e[maxN];
int cnte = 1, head[maxN];
inline void add_Edge(int i, int j) { e[++cnte].nxt = head[i], e[cnte].to = j, head[i] = cnte; }
int scc[maxN], dfn[maxN], cnt_dfn, top, stk[maxN], low[maxN], c[maxN], dis[maxN], val[maxN], cnt_scc;
bool vis[maxN], ins[maxN];
void tarjan(int u) {
    low[u] = dfn[u] = ++cnt_dfn;
    stk[++top] = u, ins[u] = true;
    for (int i = head[u], v; i; i = e[i].nxt) {
        if (!dfn[v = e[i].to]) {
            tarjan(v), low[u] = min(low[u], low[v]);
        } else if (ins[v])
            low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        Re int k;
        ++cnt_scc;
        do {
            k = stk[top--];
            ins[k] = false;
            scc[k] = cnt_scc;
            val[cnt_scc] += c[k];
        } while (k != u);
    }
}
void LPFA(int S) {
    memset(dis, -0x3f, sizeof(dis));
    queue<int> Q;
    Q.push(S), vis[S] = true, dis[S] = val[S];
    while (!Q.empty()) {
        Re int u = Q.front();
        Q.pop();
        vis[u] = false;
        for (int i = head[u]; i; i = e[i].nxt) {
            Re int v = e[i].to;
            if (dis[v] < dis[u] + val[v]) {
                dis[v] = dis[u] + val[v];
                if (!vis[v])
                    Q.push(v), vis[v] = true;
            }
        }
    }
}
int main() {
    cin >> N >> M;
    for (int i = 1; i <= M; ++i) {
        scanf("%d%d", &E[i].u, &E[i].v);
        add_Edge(E[i].u, E[i].v);
    }
    for (int i = 1; i <= N; ++i) scanf("%d", &c[i]);
    cin >> S >> P;
    for (int i = 1; i <= N; ++i)
        if (!dfn[i])
            tarjan(i);
    memset(head, 0, sizeof(head)), cnte = 1;
    for (int i = 1; i <= M; ++i)
        if (scc[E[i].u] != scc[E[i].v])
            add_Edge(scc[E[i].u], scc[E[i].v]);
    LPFA(scc[S]);
    int Ans = -1;
    for (int x, i = 1; i <= P; ++i) {
        scanf("%d", &x);
        Ans = max(Ans, dis[scc[x]]);
    }
    printf("%d\n", Ans);
    return 0;
}