#include <bits/stdc++.h>
template <class T>
bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
using namespace std;
using vint = vector<int>;
using vvint = vector<vector<int>>;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using P = pair<ll, int>;
const int inf = 1e9;
const ll inf_l = 1e18;
const int MAX = 1e5;
const int mod = 1e9 + 7;
struct union_find {
  vector<int> data;
  union_find(int size) { data.resize(size, -1); }
  int find(int x) {
    if (data[x] < 0) {
      return x;
    }
    return data[x] = find(data[x]);
  }
  bool unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) {
      return false;
    }
    if (data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return true;
  }
  int size(int x) { return -data[find(x)]; }
};
template <class T>
struct edge {
  int from, to;
  T cost;
};
template <class T>
T kruskal(vector<edge<T>> &edges, int V) {
  sort(edges.begin(), edges.end(),
       [](const edge<T> &edge1, const edge<T> &edge2) {
         return edge1.cost < edge2.cost;
       });
  union_find uf(V);
  int res = 0;
  for (edge<T> &e : edges)
    if (uf.unite(e.from, e.to)) res++;
  return res;
}
int main() {
  int n, m;
  cin >> n >> m;
  vector<edge<int>> e;
  for (int i = 0; i < (int)(m); i++) {
    int a, b, c;
    cin >> a >> b >> c;
    a--;
    b--;
    e.push_back(edge<int>{a, b, c});
  }
  cout << m - kruskal(e, n) << endl;
}
