Luogu 3627 [APIO2009]抢掠计划

Posted CzxingcHen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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("
");
    for(int i = 1; i <= n; i++)
        printf("%d ", val[i]);
    printf("
");   */
        
    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
", ans);
    return 0;
}
View Code

 

以上是关于Luogu 3627 [APIO2009]抢掠计划的主要内容,如果未能解决你的问题,请参考以下文章

Luogu 3627 [APIO2009]抢掠计划

P3627 [APIO2009]抢掠计划

p3627[APIO2009] 抢掠计划

洛谷P3627 [APIO2009]抢掠计划 缩点+spfa

[APIO2009-C]抢掠计划

[APIO2009]抢掠计划