#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr double kPI = 3.14159265358979323846264338327950288;
struct Edge {
  Edge() {}
  Edge(int u, int v) : u(u), v(v) {}
  int u;
  int v;
};
int n, m;
map<int, vector<Edge>> wedges;
vector<int> id;
int ans = 0;
void Load() {
  scanf("%d%d", &n, &m);
  id.resize(n + 1);
  for (int i = 0; i <= n; ++i) id[i] = i;
  for (int i = 0; i < m; ++i) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    wedges[w].push_back({u, v});
  }
}
int root(int v) {
  while (id[v] != v) {
    id[v] = id[id[v]];
    v = id[v];
  }
  return v;
}
void KruskalModified() {
  for (const auto& ent : wedges) {
    int w = ent.first;
    const vector<Edge> edges = ent.second;
    vector<bool> can_connect(edges.size(), false);
    int secondclass = 0;
    int es = edges.size();
    for (int i = 0; i < es; ++i) {
      const Edge& edge = edges[i];
      int v1 = root(edge.u);
      int v2 = root(edge.v);
      if (v1 == v2) continue;
      can_connect[i] = true;
      secondclass++;
    }
    for (int i = 0; i < es; ++i) {
      const Edge& edge = edges[i];
      if (!can_connect[i]) continue;
      int v1 = root(edge.u);
      int v2 = root(edge.v);
      if (v1 != v2) {
        id[v1] = v2;
      } else {
        ans++;
      }
    }
  }
}
void Solve() {
  KruskalModified();
  printf("%d\n", ans);
}
int main() {
  Load();
  Solve();
}
