1 条题解
-
0
#include <bits/stdc++.h> #define int long long using namespace std; const int MAXN = 500000; const int MAXM = 500000; // 传入两个最大次大值,返回四个数的最大次大值 pair<int, int> getMaxW(pair<int, int> a, pair<int, int> b) { if (a.first == b.first) return make_pair(a.first, max(a.second, b.second)); if (a.first > b.first) return make_pair(a.first, max(a.second, b.first)); if (a.first < b.first) return make_pair(b.first, max(a.first, b.second)); } //-----------封装LCA struct LCA { int n, root; // 点数、询问个数、根节点 vector<int> e[MAXN + 5]; // 存树 int fa[MAXN + 5]; int maxDep, dep[MAXN + 5]; int lg2[MAXN + 5]; // 替代 log2(i) int dp[MAXN][35]; // i号点的 2^j 层祖先 vector<int> ew[MAXN + 5]; // 树的边权 ----- pair<int, int> maxW[MAXN][35]; // i号点的 2^j 层最大次大边权----- // 图的初始化 void init(int _n, int _root) { n = _n; root = _root; for (int i = 1; i <= n; i++) e[i].clear(); } // 加边 void addEdge(int u, int v, int w) { e[u].push_back(v); e[v].push_back(u); ew[u].push_back(w); //----- ew[v].push_back(w); //----- } // dfs 得到父子关系、深度 void dfs(int u, int father) { fa[u] = father; for (int i = 0; i < e[u].size(); i++) { int v = e[u][i]; int w = ew[u][i]; //----- if (v == father) continue; dep[v] = dep[u] + 1; maxW[v][0] = make_pair(w, -1); //------ maxDep = max(maxDep, dep[v]); dfs(v, u); } } // lca 的初始化 void init_lca() { // 预处理:最大层数 maxDep、每个点的深度、记录父节点、log2[]、dp数组 dep[root] = 1; maxDep = 1; dfs(root, 0); lg2[1] = 0; for (int i = 2; i <= n; i++) // i == 2^(log2(i-1)+1) if (i == (1 << (lg2[i - 1] + 1))) lg2[i] = lg2[i - 1] + 1; else lg2[i] = lg2[i - 1]; for (int j = 0; j <= lg2[n]; j++) { for (int i = 1; i <= n; i++) { // 求解 dp[i][j] if (j == 0) dp[i][j] = fa[i]; else dp[i][j] = dp[dp[i][j - 1]][j - 1]; // 求解 maxW[i][j] if (j > 0) maxW[i][j] = getMaxW(maxW[i][j - 1], maxW[dp[i][j - 1]][j - 1]); } } } // 查询两个点的lca int lca(int u, int v) { if (dep[u] > dep[v]) swap(u, v); // 让u的高度不低于v if (u == v) return u; // 把 v 提到与 u 同样高度 for (int j = lg2[n]; j >= 0; j--) if ((1 << j) <= dep[v] - dep[u]) { v = dp[v][j]; } if (u == v) return u; // 找lca for (int j = lg2[n]; j >= 0; j--) if (dp[v][j] != dp[u][j]) { v = dp[v][j], u = dp[u][j]; } return dp[u][0]; } pair<int, int> queryMaxW(int u, int v) { int uv = lca(u, v); pair<int, int> res = make_pair(-1, -1); // 把 u 提到与 uv 同样高度 for (int j = lg2[n]; j >= 0; j--) if ((1 << j) <= dep[u] - dep[uv]) { res = getMaxW(res, maxW[u][j]); u = dp[u][j]; } // 把 v 提到与 uv 同样高度 for (int j = lg2[n]; j >= 0; j--) if ((1 << j) <= dep[v] - dep[uv]) { res = getMaxW(res, maxW[v][j]); v = dp[v][j]; } return res; } } lca; //-----------封装Kruskal struct kEdge { int u, v, w; bool cho; // 是否被选中了 }; bool operator<(const kEdge &a, const kEdge &b) { return a.w < b.w; } struct Kruskal { int n, m, ans; vector<kEdge> e; // 存所有的边 int fa[MAXN + 5]; int findFa(int x) { if (x == fa[x]) return x; return fa[x] = findFa(fa[x]); } void init(int _n, int _m) { n = _n; m = _m; ans = 0; for (int i = 1; i <= n; i++) fa[i] = i; } void addEdge(int u, int v, int w) { e.push_back((kEdge){u, v, w, false}); } void run() { sort(e.begin(), e.end()); for (int i = 0; i < e.size(); i++) { int u = e[i].u; int v = e[i].v; int w = e[i].w; int fU = findFa(u); int fV = findFa(v); if (fU == fV) continue; e[i].cho = true; // 这条边被选择了 ans += e[i].w; fa[fU] = fV; } } } kruskal; signed main() { ios::sync_with_stdio(false); cin.tie(0); int n, m; cin >> n >> m; kruskal.init(n, m); for (int i = 1; i <= m; i++) { int u, v, w; cin >> u >> v >> w; kruskal.addEdge(u, v, w); } kruskal.run(); lca.init(n, 1); for (int i = 0; i < kruskal.e.size(); i++) if (kruskal.e[i].cho) lca.addEdge(kruskal.e[i].u, kruskal.e[i].v, kruskal.e[i].w); lca.init_lca(); int ans = 1e18; for (int i = 0; i < kruskal.e.size(); i++) if (!kruskal.e[i].cho) { pair<int, int> maxW = lca.queryMaxW(kruskal.e[i].u, kruskal.e[i].v); int m1 = maxW.first; int m2 = maxW.second; if (m1 == kruskal.e[i].w && m2 != -1) ans = min(ans, kruskal.ans - m2 + kruskal.e[i].w); else if (m1 != kruskal.e[i].w && m1 != -1) ans = min(ans, kruskal.ans - m1 + kruskal.e[i].w); } cout << ans << "\n"; return 0; }
- 1
信息
- ID
- 785
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- 递交数
- 30
- 已通过
- 4
- 上传者