#include <bits/stdc++.h>
using namespace std;
struct node {
  int parent, children;
  node() {
    parent = -1;
    children = 1;
  }
};
int N, M;
vector<tuple<int, int, int> > edges;
int sol;
node curr[200007], past[200007];
bool comp(tuple<int, int, int> a, tuple<int, int, int> b) {
  return get<2>(a) < get<2>(b);
}
int getParent(node* n, int pos) {
  if (n[pos].parent == -1) {
    return pos;
  }
  int p = getParent(n, n[pos].parent);
  n[pos].parent = p;
  return p;
}
void join(node* n, int a, int b) {
  int pa = getParent(n, a), push_back = getParent(n, b);
  if (pa == push_back) return;
  if (n[pa].children < n[push_back].children) {
    swap(pa, push_back);
  }
  n[pa].children += n[push_back].children;
  n[push_back].parent = pa;
}
int main() {
  scanf("%d %d", &N, &M);
  for (int i = 0; i < M; i++) {
    int a, b, c;
    scanf("%d %d %d", &a, &b, &c);
    edges.push_back(make_tuple(a, b, c));
  }
  sort(edges.begin(), edges.end(), comp);
  int i = 0;
  while (i != M) {
    int cost = get<2>(edges[i]);
    int st = i, en = i;
    while (i != M && get<2>(edges[i]) == cost) {
      en = i;
      i++;
    }
    for (int j = st; j <= en; j++) {
      int a = get<0>(edges[j]), b = get<1>(edges[j]);
      if (getParent(curr, a) == getParent(curr, b)) {
        if (getParent(past, a) != getParent(past, b)) {
          sol++;
        }
      } else {
        join(curr, a, b);
      }
    }
    for (int j = st; j <= en; j++) {
      join(past, get<0>(edges[j]), get<1>(edges[j]));
    }
  }
  printf("%d\n", sol);
  return 0;
}
