zoukankan      html  css  js  c++  java
  • Codeforces #447 Div2 E

    #447 Div2 E

    题意

    给出一个由有向边构成的图,每条边上有蘑菇,假设有 (n) 个蘑菇,那么第一次走过这条边可以获得 (n) 个蘑菇,第二次 (n-1),第三次 (n-1-2),第四次 (n-1-2-3),后面类推,直至为 (0)。问从选定点出发最多可以获得几个蘑菇。

    分析

    Tarjan 算法缩点,重新给点标号(缩点),且保证了拓扑排序中靠后的点先标号,对于缩完点后的有向无环图,DP去求最长路。(对于拓扑排序后的序列,根据拓扑排序的性质,可以从后往前DP)
    拓扑排序保证了:对于有向边 (a-b)(a) 一定在 (b) 前面。

    code

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e6 + 10;
    struct Edge {
        int v, w, nxt;
    }e[N];
    int head[N], cnt;
    void addEdge(int u, int v, int w) {
        e[cnt].v = v;
        e[cnt].w = w;
        e[cnt].nxt = head[u];
        head[u] = cnt++;
    }
    int n, m, c, nn, vis[N], dfn[N], low[N];
    int f[N]; // 被缩成的新点的序号
    ll sup[N]; // 这个新点能提供的贡献
    stack<int> sta;
    vector<int> G[N];
    void tarjan(int u) { // 找强连通分量
        sta.push(u);
        dfn[u] = low[u] = ++c;
        vis[u] = 1;
        for(int i = head[u]; ~i; i = e[i].nxt) {
            int v = e[i].v;
            if(!dfn[v]) {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            } else if(vis[v] && low[u] > dfn[v]) {
                low[u] = dfn[v];
            }
        }
        if(low[u] == dfn[u]) {
            ++nn;
            while(1) {
                int id = sta.top();
                G[nn].push_back(id);
                f[id] = nn;
                sta.pop();
                vis[id] = 0;
                if(id == u) break;
            }
        }
    }
    ll calc(int w) {
        int d = sqrt(2 * w);
        while(d * d + d > 2 * w) d--;
        return 1LL * w * (d + 1) - (1LL * d * (d + 1) * (2 * d + 1) / 6 + d * (d + 1) / 2) / 2;
    }
    ll dp[N];
    int main() {
        memset(head, -1, sizeof head);
        scanf("%d%d", &n, &m);
        for(int i = 0; i < m; i++) {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            addEdge(u, v, w);
        }
        nn = n;
        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 = e[j].nxt) {
                int v = e[j].v;
                if(f[i] == f[v]) sup[f[i]] += calc(e[j].w);
            }
        }
        int s;
        scanf("%d", &s);
        s = f[s];
        for(int i = n + 1; i <= nn; i++) {
            for(int j = 0; j < G[i].size(); j++) {
                int q = G[i][j];
                for(int p = head[q]; ~p; p = e[p].nxt) {
                    int v = e[p].v;
                    if(f[q] != f[v])
                        dp[i] = max(dp[i], dp[f[v]] + sup[f[v]] + e[p].w);
                }
            }
        }
        cout << sup[s] + dp[s] << endl;
        return 0;
    }
    
  • 相关阅读:
    Session
    python内存优化机制中的小秘密
    跨域请求
    Cookie
    json
    Python深浅拷贝辨析
    Django form组件相关
    Python 中的 if __name__ == '__main__'
    online_judge_1108
    online_judge_1107
  • 原文地址:https://www.cnblogs.com/ftae/p/7881575.html
Copyright © 2011-2022 走看看