• 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
  • 相关阅读:
    spring 实现测试解耦
    Java 反射实例 (二)
    Java 反射实例
    Thread.join()
    缓存输入/输出流
    文件的拷贝
    将键盘输入的数据保存到文件中:OutputStream
    InputStream中read方法各个参数的意义
    OutputStream
    InputStream中的主要的子类
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9529574.html
Copyright © 2020-2023  润新知