解题思路:
用Kruskal的方法对边排序,遇到边权相同的一段单独处理:
①不考虑两点已经在并查集内部的(边权更小)
②将其他边拿出来,若不在相同并查集,则进行合并;如果已经在,也是相同边权的边导致的,计入答案即可
#include <bits/stdc++.h>
using namespace std ;
#define int long long
#define inf 0x3f3f3f3f3f3f3f3f
const int maxN = 2e5+10 ;
struct EDGE {
int u, v, val ;
bool operator < (const EDGE &b) const {
return val < b.val ;
}
}edges[maxN<<1] ;
struct DSU {
vector<int> fa, sz ;
DSU(int n) : fa(n+1), sz(n+1) {
for(int i=1 ; i<=n ; i++)
fa[i] = i , sz[i] = 1 ;
}
int find(int x) {
return fa[x]==x ? x : fa[x]=find(fa[x]) ;
}
void merge(int x, int y) {
x = find(x), y = find(y) ;
if(x==y) return ;
//fx -> fy
if(sz[x]>sz[y]) swap(x,y) ;
sz[y] += sz[x], fa[x]=y ;
}
} ;
signed main() {
int n , m; cin >> n >> m ;
for(int i=1 ; i<=m ; i++)
cin >> edges[i].u >> edges[i].v >> edges[i].val ;
DSU dsu(n) ;
sort(edges+1, edges+m+1) ;
int cnt = 0 , ans=0 ;
for(int l=1 , r=1 ; l<=m&&r<=m ; r=l=r+1) {
while(r<=m-1 && edges[r].val==edges[r+1].val)
r++ ;
if(l==r) {
if(dsu.find(edges[l].u)==dsu.find(edges[l].v))
continue ;
dsu.merge(edges[l].u, edges[l].v) ;
cnt++ ;
}else {
vector<int> v ;
for(int i=l ; i<=r ; i++) {
if(dsu.find(edges[i].u)==dsu.find(edges[i].v))
continue ;
v.push_back(i) ;
}
for(auto &i:v) {
if(dsu.find(edges[i].u)==dsu.find(edges[i].v)) {
ans += edges[i].val ;
}else
dsu.merge(edges[i].u, edges[i].v) , cnt++ ;
}
}
}
cout << ans << endl ;
return 0 ;
}