#include <bits/stdc++.h>
using namespace std;
class UnionFind {
 public:
  UnionFind(int rn) {
    fathers.resize(rn + 1, 0);
    for (int i = 1; i <= rn; ++i) {
      fathers[i] = i;
    }
  }
  inline void join(int x, int y) {
    int fx = findRoot(x);
    int fy = findRoot(y);
    if (fx != fy) {
      fathers[fy] = fx;
    }
  }
  inline bool same(int x, int y) { return findRoot(x) == findRoot(y); }

 private:
  vector<int> fathers;
  inline int findRoot(int number) {
    int x = number;
    while (fathers[x] != x) {
      x = fathers[x];
    }
    int y = number, temp;
    while (fathers[y] != x) {
      temp = fathers[y];
      fathers[y] = x;
      y = temp;
    }
    return x;
  }
};
struct Edge {
  Edge() {}
  Edge(const int& rfrom, const int& rto) : from(rfrom), to(rto) {}
  int from, to;
};
int main() {
  int n, m, length;
  Edge edge;
  scanf("%d %d", &n, &m);
  map<int, list<Edge> > mapping;
  for (int i = 0; i < m; ++i) {
    scanf("%d %d %d", &edge.from, &edge.to, &length);
    mapping[length].push_back(edge);
  }
  UnionFind uFind(n);
  int connection = 0, cost = 0, lastLength = 0;
  for (auto& each : mapping) {
    auto& edgeList = each.second;
    for (auto iter = edgeList.begin(); iter != edgeList.end();) {
      if (uFind.same(iter->from, iter->to)) {
        iter = edgeList.erase(iter);
      } else {
        ++iter;
      }
    }
    for (auto& e : edgeList) {
      if (!uFind.same(e.from, e.to)) {
        ++connection;
        uFind.join(e.from, e.to);
      } else {
        ++cost;
      }
    }
    if (n == connection - 1) {
      break;
    }
  }
  printf("%d\n", cost);
}
