zoukankan      html  css  js  c++  java
  • 「6月雅礼集训 2017 Day7」电报

    【题目大意】

    有n个岛屿,第i个岛屿有有向发射站到第$p_i$个岛屿,改变到任意其他岛屿需要花费$c_i$的代价,求使得所有岛屿直接或间接联通的最小代价。

    $1 leq n leq 10^5, 1 leq p_i,c_i leq 10^9$

    【题解】

    显然最后是个大环,特判原来就是大环的情况。

    考虑每个连通块最多保留多少。

    树的答案可以直接dp做出来。

    环的答案,根据树的答案dp出来。

    h[x][0/1]表示当前做到环上第i个点,环是否被切断了,的最大保留价值。

    因为环必须被切断一次。所以最后返回h[r.size()][1]即可。

    为了方便代码写的是从后向前(不会涉及到初值特判问题)

    懒得写tarjan,写的是和昨天”学外语“一样的找环方法。。

    # include <vector>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    
    const int N = 1e5 + 10, M = 2e5 + 10;
    const ll inf = 1e18;
    
    vector<int> ring[N]; int rn = 0;
    int n, p[M], c[M];
    
    int head[N], nxt[M], to[M], tot = 0, deg[N];
    inline void add(int u, int v) {
    //    cout << u << "-->" << v << endl;
        ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v;
    }
    inline void adde(int u, int v) {
        add(u, v), add(v, u);
    }
    
    namespace SOLVE_RINGS {
        struct us {
            int fa[N], n;
            inline void set(int _n) {
                n = _n; for (int i=1; i<=n; ++i) fa[i] = i;
            }
            inline int getf(int x) {
                return fa[x] == x ? x : fa[x] = getf(fa[x]);
            }
            inline void un(int fu, int fv) {
                fa[fu] = fv;
            }
        }U;
        bool inrings[N];
        int c[N], cn = 0;
        bool vis[N]; 
        inline void dfs_rings(int x) {
            if(vis[x]) {
                ++rn; for (int i=cn; i; --i) ring[rn].push_back(c[i]);
                return ;
            }
            c[++cn] = x; vis[x] = 1; 
            for (int i=head[x]; i; i=nxt[i]) ++deg[x], dfs_rings(to[i]);
            --cn;
        }
        
        inline void find_rings() {
            U.set(n);
            for (int i=1; i<=n; ++i) {
                int fu = U.getf(p[i]), fv = U.getf(i);            
                if(fu == fv) inrings[i] = 1;
                else U.un(fu, fv);
            }
            for (int i=1; i<=n; ++i) {
                if(!inrings[i]) continue;
                cn = 0;
                dfs_rings(i);
            }
        }             
        
        inline void debug_rings() {
            for (int i=1; i<=rn; ++i) {
                printf("num = %d
      ", i);
                 for (int j=0; j<ring[i].size(); ++j)
                     cout << ring[i][j] << ' ';
                cout << endl;
            }
        }
        
        inline void clear_rings() {
            for (int i=1; i<=rn; ++i) ring[i].clear(); 
            for (int i=1; i<=n; ++i) inrings[i] = vis[i] = deg[i] = 0;
            rn = 0;
        }
    }
    
    ll f[N], g[N], h[N][2];
    
    inline void dfs_trees(int x, int fa) {
        ll mx = 0;
        for (int i=head[x]; i; i=nxt[i]) {
            if(to[i] == fa) continue;
            dfs_trees(to[i], x);
            mx = max(mx, (ll)c[to[i]]);
            f[x] += f[to[i]];
        }
        g[x] = f[x];
        f[x] += mx;
    }
    
    
    inline ll solve(vector<int> r) {
        ll mx = 0, s = 0, res = 0;
        for (int i=0; i<r.size(); ++i) {
            int pr = r[(i - 1 + r.size()) % r.size()], nx = r[(i + 1) % r.size()];
            dfs_trees(r[i], pr);
        }    
        h[r.size()][1] = -inf;
        h[r.size()][0] = 0;
        for (int i=r.size() - 1; ~i; --i) {
            int pr = r[(i - 1 + r.size()) % r.size()];
            h[i][1] = h[i+1][1] + max(g[r[i]] + c[pr], f[r[i]]);
            h[i][1] = max(h[i][1], h[i+1][0] + f[r[i]]);
            h[i][0] = h[i+1][0] + g[r[i]] + c[pr];
        }
        return h[0][1];
    }
    
    int main() {
    //    freopen("telegraph.in", "r", stdin);
    //    freopen("telegraph.out", "w", stdout);
        cin >> n;
        for (int i=1; i<=n; ++i) {
            scanf("%d%d", p+i, c+i);
            add(p[i], i);
        }
        SOLVE_RINGS :: find_rings();
        if(rn == 1 && ring[rn].size() == n) {
            puts("0");
            return 0;
        }
    //    SOLVE_RINGS :: debug_rings();
        ll ans = 0, sum = 0;
        for (int i=1; i<=rn; ++i) ans += solve(ring[i]);
        for (int i=1; i<=n; ++i) sum += c[i];
        cout << sum - ans;
        return 0;
    }
    View Code
  • 相关阅读:
    攻防世界-进阶-1-re4-unvm-me
    攻防世界-reverse-7(game)
    攻防世界-reverse-4.5.6
    20199312 2019-2020-2 《网络攻防实践》第6周作业
    攻防世界-reverse-1.2.3
    pwndbg+kali 爬坑
    第五课 实践验收
    20199315 2019-2020-2 《网络攻防实践》第5周作业
    实践三 网络嗅探与协议分析
    20199315 2019-2020-2 《网络攻防实践》第4周作业
  • 原文地址:https://www.cnblogs.com/galaxies/p/20170623_a.html
Copyright © 2011-2022 走看看