P4180 嚴格次小生成樹[BJWC2010] Kruskal,倍增
阿新 • • 發佈:2019-04-27
pac rhs std cout name 怎麽 head edge names
題目鏈接\(Click\) \(Here\)。
題意就是要求一個圖的嚴格次小生成樹。以前被題面嚇到了沒敢做,寫了一下發現並不難。
既然要考慮次小我們就先考慮最小。可以感性理解到一定有一種次小生成樹,可以由最小生成樹刪一條邊再加一條邊得到。我們枚舉加上去的這一條邊,加上去以後原\(mst\)會成為一個基環樹,想讓它次小就在這個環裏找一條最長的邊(不包含新加進去的)刪掉就好。放在樹上來講,就是找到\(u\)到\(v\)路徑上的最大值。這樣我們就有了非嚴格次小生成樹。
嚴格要怎麽處理?我們需要排除新加上的邊和\(u\)到\(v\)路徑最長邊相等的情況。仔細思考會發現可以再倍增維護一個次大長度,如果最大長度嚴格小於新加上邊的長度就選用最大,否則就用次大。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 100000 + 5; const int M = 300000 + 5; const int INF = 0x7fffffff; const LL INFF = 0x7fffffffffffffff; struct Graph { int cnt, head[N]; struct Edge {int nxt, to, w;}e[N << 1]; void clear () { cnt = -1; memset (head, -1, sizeof (head)); } void add_len (int u, int v, int w) { e[++cnt] = (Edge) {head[u], v, w}; head[u] = cnt; e[++cnt] = (Edge) {head[v], u, w}; head[v] = cnt; } int deep[N], pre[N][20], w1st[N][20], w2nd[N][20]; void dfs (int u, int fa) { deep[u] = deep[fa] + 1; for (int i = head[u]; ~i; i = e[i].nxt) { int v = e[i].to; if (v != fa) { dfs (v, u); pre[v][0] = u; w2nd[v][0] = -INF; w1st[v][0] = e[i].w; } } } void build (int u) { for (int i = 1; (1 << i) <= deep[u]; ++i) { pre[u][i] = pre[pre[u][i - 1]][i - 1]; w1st[u][i] = max (w1st[u][i - 1], w1st[pre[u][i - 1]][i - 1]); w2nd[u][i] = max (w2nd[u][i - 1], w2nd[pre[u][i - 1]][i - 1]); if (w1st[u][i - 1] < w1st[pre[u][i - 1]][i - 1]) { w2nd[u][i] = max (w2nd[u][i], w1st[u][i - 1]); } if (w1st[u][i - 1] > w1st[pre[u][i - 1]][i - 1]) { w2nd[u][i] = max (w2nd[u][i], w1st[pre[u][i - 1]][i - 1]); } } for (int i = head[u]; ~i; i = e[i].nxt) { if (e[i].to != pre[u][0]) build (e[i].to); } } int lca (int u, int v) { if (deep[u] < deep[v]) swap (u, v); for (int i = 19; i >= 0; --i) { if (deep[u] - deep[v] >= (1 << i)) { u = pre[u][i]; } } if (u == v) return u; for (int i = 19; i >= 0; --i) { if (pre[u][i] != pre[v][i]) { u = pre[u][i]; v = pre[v][i]; } } return pre[u][0]; } int query (int u, int v, int w) { //求u到v之間嚴格小於w的最大的值 int ans = -INF; for (int i = 19; i >= 0; --i) { if (deep[v] - deep[u] >= (1 << i)) { if (w1st[v][i] < w) { ans = max (ans, w1st[v][i]); } else { ans = max (ans, w2nd[v][i]); } v = pre[v][i]; } } return ans; } }G; struct Len { int u, v, w; bool operator < (Len rhs) const { return w < rhs.w; } Len () {} Len (int u, int v, int w) : u(u), v(v), w(w) {} }arr[M]; int n, m, Set[N], in_mst[M]; int find (int x) { return x == Set[x] ? x : (Set[x] = find (Set[x])); } int main () { G.clear (); cin >> n >> m; for (int i = 0; i < m; ++i) { static int u, v, w; cin >> u >> v >> w; arr[i] = Len (u, v, w); } sort (arr, arr + m); for (int i = 0; i <= n; ++i) Set[i] = i; LL mstw = 0; for (int i = 0; i < m; ++i) { int u = arr[i].u; int v = arr[i].v; int w = arr[i].w; if (find (u) != find (v)) { mstw += w; in_mst[i] = true; G.add_len (u, v, w); Set[find (u)] = find (v); } } G.w1st[1][0] = -INF; G.dfs (1, 0); G.build (1); LL ans = INFF; for (int i = 0; i < m; ++i) { if (!in_mst[i]) { int u = arr[i].u; int v = arr[i].v; int w = arr[i].w; int _lca = G.lca (u, v); int maxu = G.query (_lca, u, w); int maxv = G.query (_lca, v, w); ans = min (ans, mstw + w - max (maxu, maxv)); } } cout << ans << endl; }
P4180 嚴格次小生成樹[BJWC2010] Kruskal,倍增