#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9 + 7;
typedef struct edge {
  int u;
  int v;
  int cost;
} EDGE;
typedef struct union_find {
  vector<long long> pa;
  vector<long long> ra;
  vector<long long> siz;
  void init(long long n) {
    pa.resize(n);
    ra.resize(n);
    siz.resize(n);
    for (long long i = 0; i < n; i++) {
      pa[i] = i;
      ra[i] = 0LL;
      siz[i] = 0LL;
    }
  }
  long long find(long long x) {
    if (pa[x] == x) {
      return x;
    } else {
      return pa[x] = find(pa[x]);
    }
  }
  void unite(long long x, long long y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return;
    }
    pa[y] = x;
    siz[x] += siz[y] + 1;
  }
  bool same(long long x, long long y) { return find(x) == find(y); }
} UF;
long long kruskal(long long n, long long m, vector<EDGE>& es,
                  union_find& tree) {
  long long res = 0;
  for (long long i = 0; i < m; i++) {
    EDGE e = es[i];
    if (!tree.same(e.u, e.v)) {
      tree.unite(e.u, e.v);
    }
  }
  return m - tree.siz[tree.find(1)];
}
bool comp(const EDGE& a, EDGE& b) { return a.cost < b.cost; }
int main() {
  long long n, m;
  UF tree;
  cin >> n >> m;
  tree.init(n + 10);
  vector<EDGE> es(m);
  for (int i = 0; i < m; i++) {
    cin >> es[i].u >> es[i].v >> es[i].cost;
  }
  sort(es.begin(), es.end(), comp);
  long long ans = kruskal(n, m, es, tree);
  cout << ans << endl;
  return 0;
}
