【YBTOJ】【Luogu P4180】[BJWC2010]嚴格次小生成樹
阿新 • • 發佈:2021-07-08
【YBTOJ】【Luogu P4180】[BJWC2010]嚴格次小生成樹:
連結:
題目大意:
求次小生成樹。
正文:
本題有一個至關重要的性質:次小生成樹只與最小生成樹有一邊之差。
那麼只用在最小生成樹中加邊,在環中的邊裡找一個最大的邊減去。將所有這樣的操作取最大,就是非嚴格最小生成樹。有個“非”,是因為最大的邊權可能與加邊的邊權相等,所以遇到這種情況要取次大值。
倍增操作求值就能解決問題了。
程式碼:
const int N = 1e5 + 10, M = 3e5 + 10; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } // main int n, m; int logN; ll ans = 1e17, sum; // edge struct Edge { struct edge { int from, to, nxt;ll val; bool t; bool operator < (edge &a) const { return val < a.val; } }e[M << 1]; int head[N], tot; void add(int u, int v, ll w) { e[++tot] = (edge) {u, v, head[u], w, 1}, head[u] = tot; } } g, t; // Kruskal int fa[N]; int Find(int k) {return k == fa[k]? k: fa[k] = Find(fa[k]);} void Kruskal() { sort (g.e + 1, g.e + 1 + m); for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= m; i++) { int u = Find(g.e[i].from), v = Find(g.e[i].to); if (u == v) continue; fa[u] = v; sum += g.e[i].val; t.add(g.e[i].from, g.e[i].to, g.e[i].val); t.add(g.e[i].to, g.e[i].from, g.e[i].val); g.e[i].t = 0; } } // LCA int dep[N]; bool vis[N]; int f[N][30]; ll Max[N][30], sMax[N][30]; queue <int> q; void BFS(int root) { while(!q.empty()) q.pop(); q.push(root); dep[root] = 1; while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 1; for (int i = t.head[u]; i; i = t.e[i].nxt) { int v = t.e[i].to; if (vis[v]) continue; dep[v] = dep[u] + 1; Max[v][0] = t.e[i].val; sMax[v][0] = -1e17; f[v][0] = u; for (int j = 1; j <= logN; j++) { f[v][j] = f[f[v][j - 1]][j - 1]; sMax[v][j] = max(sMax[v][j - 1], sMax[f[v][j - 1]][j - 1]); Max[v][j] = max(Max[v][j - 1], Max[f[v][j - 1]][j - 1]); if (Max[v][j - 1] > Max[f[v][j - 1]][j - 1]) sMax[v][j] = max(sMax[v][j], Max[f[v][j - 1]][j - 1]); if (Max[v][j - 1] < Max[f[v][j - 1]][j - 1]) sMax[v][j] = max(sMax[v][j], Max[v][j - 1]); } q.push(v); } } } int LCA(int u, int v) { if (dep[u] > dep[v]) u ^= v ^= u ^= v; for (int j = logN; ~j; j--) if(dep[f[v][j]] >= dep[u]) v = f[v][j]; if (u == v) return u; for (int j = logN; ~j; j--) if(f[v][j] != f[u][j]) v = f[v][j], u = f[u][j]; u = f[u][0], v = f[v][0]; return u; } ll solve (int u, int v, ll k) { ll ans = -1e17; for (int j = logN; ~j; j--) if(dep[f[u][j]] >= dep[v]) { if (k != Max[u][j]) ans = max(ans, Max[u][j]); else ans = max(ans, sMax[u][j]); u = f[u][j]; } return ans; } // main() int main() { n = Read(), m = Read(); logN = log2(m) + 1; for (int i = 1; i <= m; i++) { int u = Read(), v = Read(); ll w = Read(); g.add(u, v, w); } Kruskal(); BFS(1); for (int i = 1; i <= m; i++) { if (!g.e[i].t) continue; int u = g.e[i].from, v = g.e[i].to; ll tmp = sum, w = g.e[i].val; int c = LCA(u, v); tmp = tmp + w - max(solve (u, c, w), solve (v, c, w)); ans = min(ans, tmp); } printf ("%lld\n", ans); return 0; }