#include <bits/stdc++.h>
using namespace std;
const int INF = 1001001000;
const int mINF = -1001001000;
const long long LINF = 1010010010010010000;
template <class T>
inline bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
inline bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
struct UnionFind {
  vector<int> par, depth, Size;
  UnionFind(int n) {
    par.resize(n);
    depth.resize(n);
    Size.resize(n);
    for (int i = 0; i < n; i++) {
      par[i] = i;
      depth[i] = 0;
      Size[i] = 1;
    }
  }
  int find(int x) {
    if (par[x] == x) {
      return x;
    } else {
      return par[x] = find(par[x]);
    }
  }
  bool same(int x, int y) { return find(x) == find(y); }
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (depth[x] < depth[y]) swap(x, y);
    if (depth[x] == depth[y]) depth[x]++;
    par[y] = x;
    Size[x] += Size[y];
  }
  int size(int x) { return Size[find(x)]; }
};
struct edges {
  int from, to, cost;
  bool operator<(const edges& e) const { return (cost < e.cost); }
};
int main() {
  int n, m;
  cin >> n >> m;
  vector<edges> v(m);
  for (int i = 0; i < m; i++) {
    cin >> v[i].from >> v[i].to >> v[i].cost;
  }
  sort(v.begin(), v.end());
  UnionFind uf(n + 1);
  int ans = 0;
  for (int i = 0; i < m; i++) {
    if (!uf.same(v[i].from, v[i].to)) {
      uf.unite(v[i].from, v[i].to);
      ans++;
    }
  }
  ans = m - ans;
  cout << ans << endl;
  return 0;
}
