#include <bits/stdc++.h>
using namespace std;
class UnionFind {
 private:
  int size_;
  vector<int> par, rank;

 public:
  UnionFind() : size_(0), par(vector<int>(0)), rank(vector<int>(0)) {}
  UnionFind(int size_) : size_(size_) {
    par.resize(size_), rank.resize(size_);
    for (int i = 0; i < (size_); ++i) par[i] = i, rank[i] = 0;
  }
  int size() { return size_; }
  int root(int x) { return (par[x] == x) ? x : par[x] = root(par[x]); }
  void unite(int x, int y) {
    x = root(x), y = root(y);
    if (x == y) return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y) { return root(x) == root(y); }
};
struct edge {
  int u, v, cost;
  edge(int u, int v, int cost) : u(u), v(v), cost(cost) {}
};
bool comp(const edge &e1, const edge &e2) { return e1.cost < e2.cost; }
vector<edge> es;
int n, m, a, b, c;
int kruskal() {
  int ret = 0;
  sort(es.begin(), es.end(), comp);
  UnionFind uf(n);
  for (int i = 0; i < es.size(); ++i) {
    edge e = es[i];
    if (!uf.same(e.u, e.v)) {
      uf.unite(e.u, e.v);
    } else {
      ret++;
    }
  }
  return ret;
}
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin >> n >> m;
  for (int i = 0; i < m; ++i) {
    cin >> a >> b >> c;
    es.push_back(edge(a - 1, b - 1, c - 1));
  }
  cout << kruskal() << endl;
}
