#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+10; int n,m; int p[N]; struct edge{ int a,b; int w; }e[N]; bool cmp(edge a,edge b) { return a.w<b.w; } int find(int x) { if(p[x]!=x) p[x]=find(p[x]); return p[x]; } void Unit(int x,int y) { int px=find(x); int py=find(y); if(px!=py) p[px]=py; } int main() { while(cin>>n>>m) { for(int i=1;i<=n;i++) p[i]=i; for(int i=0;i<m;i++) cin>>e[i].a>>e[i].b>>e[i].w; sort(e,e+m,cmp); int ans=0; for(int i=0;i<m;) { int num=0; int j=i; //找到边权相同的尾部坐标 while(e[i].w==e[j].w) j++; //从i到j都是边权最小且相同的边 for(int k=i;k<j;k++) { int pa=find(e[k].a); int pb=find(e[k].b); //统计可以选择的合法边的数量 if(pa!=pb) num++; } for(int k=i;k<j;k++) { int pa=find(e[k].a); int pb=find(e[k].b); //从合法边中减去非冲突边(即可以被选入到同一个方案里,不互相冲突的边) //比如 有两条边是相同的 //如果选择第一条之后,fx=fy //遍历到第二条时,num--就不能进行 if(pa!=pb) Unit(pa,pb),num--; } i=j; //冲突边 = 合法边 - 非冲突边 ans+=num; } cout<<ans<<endl; } }