【题目大意】
有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\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; }
时间: 2024-10-29 04:16:54