#include <bits/stdc++.h>
using namespace std;
const int INTMAX = 2147483647;
const int64_t LLMAX = 9223372036854775807;
const int MOD = 1000000007;
template <class T>
inline bool chmax(T& a, const T& b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
inline bool chmin(T& a, const T& b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
inline void swap(int64_t& a, int64_t& b) {
  a ^= b;
  b ^= a;
  a ^= b;
}
inline void swap(int& a, int& b) {
  a ^= b;
  b ^= a;
  a ^= b;
}
auto compare = [](const tuple<int64_t, int, int>& left,
                  const tuple<int64_t, int, int>& right) {
  return get<0>(left) < get<0>(right);
};
int n, m, n_mst = 0;
int64_t c_mst = 0;
vector<tuple<int64_t, int, int> > e, mst;
vector<int> parent;
void init() {
  cin >> n >> m;
  e.reserve(m);
  parent.resize(n, -1);
  for (int i{0}; i < (int)(m); i++) {
    int a, b;
    int64_t c;
    cin >> a >> b >> c;
    if (a > b) swap(a, b);
    --a;
    --b;
    e.emplace_back(tuple<int64_t, int, int>(c, a, b));
  }
  sort((e).begin(), (e).end(), compare);
}
int root(int a) {
  if (parent[a] < 0) return a;
  return parent[a] = root(parent[a]);
}
bool unite(const tuple<int64_t, int, int>& edge) {
  int a = get<1>(edge);
  int b = get<2>(edge);
  int64_t c = get<0>(edge);
  int root_a = root(a);
  int root_b = root(b);
  if (root_a == root_b) return false;
  int size_a = -parent[root_a];
  int size_b = -parent[root_b];
  if (size_a < size_b) {
    swap(a, b);
    swap(size_a, size_b);
  }
  parent[a] += -size_b;
  parent[b] = a;
  ++n_mst;
}
int main() {
  init();
  for (auto edge : e) unite(edge);
  cout << (m - n_mst) << endl;
}
