#include <bits/stdc++.h>
using namespace std;
const int N = 900010;
int n, m;
int x[N], y[N], c[N], disc[N], cnt, id[N];
struct dinic {
  vector<pair<int, int> > edge;
  vector<vector<int> > G;
  vector<int> d, cur;
  int sz;
  dinic() {
    sz = 0;
    G.resize(0);
    edge.resize(0);
    d.resize(0);
    cur.resize(0);
  }
  void clr() {
    sz = 0;
    G.resize(0);
    edge.resize(0);
    d.resize(0);
    cur.resize(0);
  }
  void init(int SZ) {
    sz = SZ;
    G.resize(SZ + 2);
    d.resize(SZ + 2);
    cur.resize(SZ + 2);
  }
  void add(int u, int v, int c) {
    edge.push_back(make_pair(v, c));
    G[u].push_back(edge.size() - 1);
    edge.push_back(make_pair(u, 0));
    G[v].push_back(edge.size() - 1);
  }
  bool bfs(int s, int t) {
    for (int i = (1); i <= (sz); ++i) d[i] = sz + 1, cur[i] = 0;
    queue<int> q;
    q.push(s);
    d[s] = 0;
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      for (int i = (0); i <= ((int)(G[u].size() - 1)); ++i) {
        pair<int, int> E = edge[G[u][i]];
        if (E.second && d[u] + 1 < d[E.first])
          d[E.first] = d[u] + 1, q.push(E.first);
      }
    }
    return d[t] < sz + 1;
  }
  int dfs(int u, int fl, int t) {
    if (u == t || !fl) return fl;
    int f = 0, tm;
    for (int& i = cur[u]; i < G[u].size(); ++i) {
      pair<int, int>& E = edge[G[u][i]];
      if (d[u] + 1 == d[E.first] && (tm = dfs(E.first, min(fl, E.second), t))) {
        fl -= tm;
        f += tm;
        E.second -= tm;
        edge[G[u][i] ^ 1].second += tm;
        if (!fl) break;
      }
    }
    return f;
  }
  int maxflow(int s, int t) {
    int ans = 0;
    while (bfs(s, t)) ans += dfs(s, 0x3f3f3f3f, t);
    return ans;
  }
} Flow;
vector<pair<int, int> > g[N];
int vis[N], fa[N], up[N];
vector<int> cyc[N];
int pos[N];
int cyc_cnt;
void dfs(int u) {
  for (int i = 0; i < g[u].size(); ++i) {
    int v = g[u][i].first, w = g[u][i].second;
    if (!vis[v]) {
      vis[v] = vis[u] + 1;
      fa[v] = u;
      up[v] = w;
      dfs(v);
    } else if (v != fa[u]) {
      int tu = u, tv = v;
      if (tu > tv) continue;
      if (vis[tu] < vis[tv]) swap(tu, tv);
      ++cyc_cnt;
      while (vis[tu] > vis[tv]) cyc[cyc_cnt].push_back(up[tu]), tu = fa[tu];
      while (tu != tv) {
        cyc[cyc_cnt].push_back(up[tu]);
        cyc[cyc_cnt].push_back(up[tv]);
        tu = fa[tu];
        tv = fa[tv];
      }
      cyc[cyc_cnt].push_back(w);
    }
  }
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; ++i) {
    scanf("%d%d%d", &x[i], &y[i], &c[i]);
    disc[++cnt] = c[i];
  }
  sort(disc + 1, disc + 1 + cnt);
  cnt = unique(disc + 1, disc + 1 + cnt) - (disc + 1);
  for (int i = 1; i <= m; ++i)
    c[i] = lower_bound(disc + 1, disc + 1 + cnt, c[i]) - disc;
  int tot = 0;
  for (int i = 1; i <= cnt; ++i) id[i] = ++tot;
  for (int i = 1; i <= m; ++i) {
    g[x[i]].push_back({y[i], i});
    g[y[i]].push_back({x[i], i});
  }
  for (int i = 1; i <= n; ++i)
    if (!vis[i]) {
      vis[i] = 1;
      dfs(i);
    }
  vector<bool> mark(m + 1, false);
  for (int i = 1; i <= cyc_cnt; ++i) pos[i] = ++tot;
  int S = ++tot, T = ++tot;
  Flow.init(tot + 5);
  for (int i = 1; i <= cyc_cnt; ++i)
    if (cyc[i].size()) {
      Flow.add(S, pos[i], (int)cyc[i].size() - 1);
      for (int num : cyc[i]) mark[num] = 1;
      for (int num : cyc[i]) Flow.add(pos[i], id[c[num]], 1);
    }
  for (int i = 1; i <= m; ++i)
    if (!mark[i]) Flow.add(S, id[c[i]], 1);
  for (int i = 1; i <= cnt; ++i) Flow.add(id[i], T, 1);
  int f = Flow.maxflow(S, T);
  cout << f << '\n';
  return 0;
}
