先把k个边加进去, 然后用m条边从小到达能加就加, 那么对于m条边中剩余的那些边(u, v, w)
只有在树形成的路径(u, v)上存在一条比w大的边才能放进去, 那么路径(u, v)上所有边小于等于w
用每条边更新一次用并查集维护, 用st表压标记可能会T。
#include<bits/stdc++.h> #define LL long long #define fi first #define se second #define mk make_pair #define PII pair<int, int> using namespace std; const int N = (int)5e5 + 7; const int inf = 0x3f3f3f3f; int n, k, m, id[N], val[N], pa[N], depth[N]; vector<PII> G[N]; vector<pair<PII, int>> V; int fa[N]; int getRoot(int x) { return fa[x] == x ? x : fa[x] = getRoot(fa[x]); } bool unite(int x, int y) { x = getRoot(x); y = getRoot(y); if(x == y) return false; fa[y] = x; return true; } void dfs(int u, int fa) { depth[u] = depth[fa] + 1; pa[u] = fa; for(auto &e : G[u]) { if(e.se == fa) continue; id[e.se] = e.fi; dfs(e.se, u); } } int main() { scanf("%d%d%d", &n, &k, &m); for(int i = 1; i <= n; i++) fa[i] = i; for(int i = 1; i <= k; i++) val[i] = inf; for(int i = 1; i <= k; i++) { int u, v; scanf("%d%d", &u, &v); G[u].push_back(mk(i, v)); G[v].push_back(mk(i, u)); unite(u, v); } for(int i = 1; i <= m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); if(unite(u, v)) { G[u].push_back(mk(0, v)); G[v].push_back(mk(0, u)); } else { V.push_back(mk(mk(u, v), w)); } } dfs(1, 0); for(int i = 1; i <= n; i++) fa[i] = i; for(auto &t : V) { int u = t.fi.fi, v = t.fi.se, w = t.se; u = getRoot(u); v = getRoot(v); while(u != v) { if(depth[u] >= depth[v]) val[id[u]] = w, unite(pa[u], u); else val[id[v]] = w, unite(pa[v], v); u = getRoot(u); v = getRoot(v); } } LL ans = 0; for(int i = 1; i <= k; i++) { if(val[i] >= inf) { puts("-1"); return 0; } ans += val[i]; } printf("%lld ", ans); return 0; }