「6月雅禮集訓 2017 Day7」電報
阿新 • • 發佈:2017-06-23
連通塊 print 要花 style view 最小 pre mes freopen
【題目大意】
有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; vectorView Code<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\n ", 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; }
「6月雅禮集訓 2017 Day7」電報