BZOJ1977[BJOI2010] 次小生成樹
阿新 • • 發佈:2018-09-27
con getchar() 過程 else if tin min cmp efi lse
題目藍鏈
Solution
考慮首先建出一棵最小生成樹,然後再枚舉所有其他的邊。然後直接查詢這條邊對應在樹上的兩點之間的鏈上最大值和次大值,因為要保證嚴格次小。然後用查詢的值更新一下答案
維護一條鏈上的最大值和次大值,直接倍增就行了
Code
#include <bits/stdc++.h> using namespace std; #define squ(x) ((LL)(x) * (x)) #define debug(...) fprintf(stderr, __VA_ARGS__) typedef long long LL; typedef pair<int, int> pii; inline int read() { int sum = 0, fg = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) fg = -1; for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30); return fg * sum; } const int maxn = 1e5 + 10; const int maxm = 3e5 + 10; const LL inf = 0x3f3f3f3f3f3f3f3f; int n, m; bool b[maxm]; struct edge { int x, y, z; bool operator < (const edge &t) const { return z < t.z; } }e[maxm]; vector<pii> g[maxn]; namespace MST { int fa[maxn]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } LL kruskal() { LL res = 0; sort(e + 1, e + m + 1); for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= m; i++) { int x = find(e[i].x), y = find(e[i].y); if (x == y) continue; g[e[i].x].push_back((pii){e[i].y, e[i].z}); g[e[i].y].push_back((pii){e[i].x, e[i].z}); fa[x] = y; res += e[i].z; b[i] = 1; } return res; } } struct node { int x, y; node(int _x = -1, int _y = -1): x(_x), y(_y) { } }Max[maxn][17]; bool cmp(int x, int y) { return x > y; } int t[5]; node merge(const node &a, const node &b) { t[0] = a.x, t[1] = a.y; t[4] = b.x, t[3] = b.y; sort(t, t + 5, cmp); unique(t, t + 5); return (node){t[0], t[1]}; } int fa[maxn][17], d[maxn]; void dfs(int now, int f) { fa[now][0] = f, d[now] = d[f] + 1; for (int i = 1; i <= 16; i++) { fa[now][i] = fa[fa[now][i - 1]][i - 1]; Max[now][i] = merge(Max[now][i - 1], Max[fa[now][i - 1]][i - 1]); } for (int i = 0; i < g[now].size(); i++) { int son = g[now][i].first, ds = g[now][i].second; if (son == f) continue; Max[son][0] = (node){ds, -1}; dfs(son, now); } } node find(int x, int y) { if (d[x] < d[y]) swap(x, y); node res = (node){-1, -1}; for (int i = 16; ~i; i--) if (d[fa[x][i]] >= d[y]) res = merge(res, Max[x][i]), x = fa[x][i]; if (x == y) return res; for (int i = 16; ~i; i--) if (fa[x][i] != fa[y][i]) { res = merge(res, Max[x][i]); res = merge(res, Max[y][i]); x = fa[x][i], y = fa[y][i]; } res = merge(res, Max[x][0]); res = merge(res, Max[y][0]); return res; } int main() { #ifdef xunzhen freopen("tree.in", "r", stdin); freopen("tree.out", "w", stdout); #endif n = read(); m = read(); for (int i = 1; i <= m; i++) { int x = read(), y = read(), z = read(); e[i] = (edge){x, y, z}; } LL sum = MST :: kruskal(), ans = inf; t[4] = -1, dfs(1, 0); for (int i = 1; i <= m; i++) if (!b[i]) { node res = find(e[i].x, e[i].y); if (e[i].z > res.x) ans = min(ans, sum + e[i].z - res.x); else if (e[i].z > res.y) ans = min(ans, sum + e[i].z - res.y); } printf("%lld\n", ans); return 0; }
Summary
這道題的思路不是很難,結果在碼碼的過程中出現了很多SB錯誤,調了我一個小時才調出來...
BZOJ1977[BJOI2010] 次小生成樹