• 【Codeforces】894E.Ralph and Mushrooms Tarjan缩点+DP


    题意

    给定$n$个点$m$条边有向图及边权$w$,第$i$次经过一条边边权为$w-1-2.-..-i$,$wge 0$给定起点$s$问从起点出发最多能够得到权和,某条边可重复经过


    有向图能够重复经过的边当且仅当成环,所以tarjan缩点成DAG,缩点后每个点内的权值可以通过二分算出,假设最大的$n$使得$w-frac{n(n+1)}{2}ge 0$,那么该点值为$(n+1)w-frac{n(n+1)(n+2)}{6}$,通过对DAG进行dp算出最长路就是答案

    代码

    #include <bits/stdc++.h>
    #define inf 0x7f7f7f7f
    using namespace std;
    typedef long long LL;
    const int N = 1000005;
    int n, m, x, y, w, s;
    int head[N], nxt[N], to[N], val[N], cnt;
    inline void init(){memset(head, -1, sizeof(head)); cnt = 0;}
    inline void add(int u, int v, int w) {to[cnt] = v, val[cnt] = w, nxt[cnt] = head[u], head[u] = cnt++;}
    int head2[N], nxt2[N], to2[N], cnt2; LL val2[N];
    inline void init2() {memset(head2, -1, sizeof(head)); cnt2 = 0;}
    inline void add2(int u, int v, LL w) {to2[cnt2] = v, val2[cnt2] = w, nxt2[cnt2] = head2[u], head2[u] = cnt2++;}
    int dfs_ind = 1, dfn[N], low[N], sccno[N], scc_cnt = 0;
    LL w_[N];
    stack<int> st;
    void tarjan(int u) {
        dfn[u] = low[u] = dfs_ind++;
        st.push(u);
        for(int i = head[u]; ~i; i = nxt[i]) {
            int v = to[i];
            if(!dfn[v]) {tarjan(v); low[u] = min(low[u], low[v]);}
            else if(!sccno[v]) {low[u] = min(low[u], dfn[v]);}
        }
        if(dfn[u] == low[u]) {
            scc_cnt++;
            while(1) {
                int x = st.top(); st.pop();
                sccno[x] = scc_cnt;
                if(x == u) break;
            }
        }
    }
    inline LL cal(LL x) {
        LL n = sqrt(2.0 * x + 0.25) - 0.5;
        return (n + 1) * x - (n + 1) * (n + 2) * n / 6;
    }
    void DAG() {
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(sccno,0,sizeof(sccno));
        memset(w_,0,sizeof(w_));
        init2();
        for(int i = 1; i <= n; ++i) if(!dfn[i]) tarjan(i);
        for(int i = 1; i <= n; ++i) {
            for(int j = head[i]; ~j; j = nxt[j]) {
                int v = to[j];
                if(sccno[i] != sccno[v]) {
                    add2(sccno[i], sccno[v], 1LL * val[j]);
                }else w_[sccno[i]] += cal(val[j]);
            }
        }
    }
    LL dp[N];
    void dfs(int u) {
        if(~dp[u]) return;
        dp[u] = w_[u];
        for(int i = head2[u]; ~i; i = nxt2[i]) {
            dfs(to2[i]);
            dp[u] = max(dp[u], w_[u] + dp[to2[i]] + val2[i]);
        }
    }
    int main() {
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; ++i) {
            scanf("%d%d%d", &x, &y, &w);
            add(x, y, w);
        }
        scanf("%d", &s);
        DAG();
        memset(dp, -1, sizeof(dp));
        dfs(sccno[s]);
        cout << dp[sccno[s]] << endl;
        return 0;
    }
    
  • 相关阅读:
    《转》MFC六大关键技术之(五)(六)——消息映射与命令传递
    《转》MFC六大关键技术之(四)——永久保存(串行化)
    《转》MFC六大关键技术之(三)——动态创建
    《转》MFC六大关键技术之(二)——运行时类信息(RTTI)
    《转》MFC六大关键技术之(一)—— 初始化过程
    C++ 语言的 15 个晦涩特性
    QT的项目管理文件pro的编写
    使用C++编写的一个Find(查找)对话框例子
    如何让Fedora能够打开RAR文件
    Undefined symbols for architecture i386:和"_OBJC_CLASS_$_xx", referenced from:问题解决方法
  • 原文地址:https://www.cnblogs.com/ogiso-setsuna/p/7930209.html
Copyright © 2020-2023  润新知