#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <typename T>
using PQ = priority_queue<T>;
template <typename T>
using GPQ = priority_queue<T, vector<T>, greater<T>>;
template <class L, class R>
ostream& operator<<(ostream& os, pair<L, R> p);
template <class T>
ostream& operator<<(ostream& os, vector<T> v) {
  os << "[";
  for (auto vv : v) os << vv << ",";
  return os << "]";
}
template <class T>
ostream& operator<<(ostream& os, set<T> v) {
  os << "[";
  for (auto vv : v) os << vv << ",";
  return os << "]";
}
template <class L, class R>
ostream& operator<<(ostream& os, pair<L, R> p) {
  return os << "(" << p.first << "," << p.second << ")";
}
template <typename T>
inline T sq(T a) {
  return a * a;
}
template <typename T>
T gcd(T a, T b) {
  if (a < b) return gcd(b, a);
  return b == 0 ? a : gcd(b, a % b);
}
template <typename T, typename U>
T mypow(T b, U n) {
  if (n == 0) return 1;
  if (n == 1) return b;
  if (n % 2 == 0) {
    return mypow(b * b, n / 2);
  } else {
    return mypow(b, n - 1) * b;
  }
}
ll pcnt(ll b) { return __builtin_popcountll(b); }
template <typename T>
T iceil(T n, T d) {
  return (n + d - 1) / d;
}
ll X[100010];
class persistentUF {
 public:
  explicit persistentUF(int N) : V_NUM(N), now(0) {
    par.resize(V_NUM);
    rank.resize(V_NUM);
    num.resize(V_NUM);
    tim.resize(V_NUM);
    c.resize(V_NUM);
    for (int i = 0; i < V_NUM; ++i) {
      par[i] = i;
    }
    fill(rank.begin(), rank.end(), 0);
    fill(tim.begin(), tim.end(), INF);
    for (int i = 0; i < V_NUM; ++i) {
      num[i].push_back(make_pair(0, 1));
      c[i].push_back(make_pair(0, X[i]));
    }
  }
  int find(int x, int t) {
    if (tim[x] > t) return x;
    return find(par[x], t);
  }
  void unite(int x, int y) {
    ++now;
    x = find(x, now);
    y = find(y, now);
    if (x == y) return;
    if (rank[x] < rank[y]) swap(x, y);
    num[x].push_back(make_pair(now, size(x, now) + size(y, now)));
    c[x].push_back(make_pair(now, cost(x, now) + cost(y, now)));
    par[y] = x;
    tim[y] = now;
    if (rank[x] == rank[y]) ++rank[x];
  }
  bool same(int x, int y, int t) { return find(x, t) == find(y, t); }
  bool ispar(int x, int t) { return x == find(x, t); }
  int size(int x, int t) {
    x = find(x, t);
    int ok = 0, ng = num[x].size();
    while (ng - ok > 1) {
      int mid = (ok + ng) / 2;
      if (num[x][mid].first <= t) {
        ok = mid;
      } else {
        ng = mid;
      }
    }
    return num[x][ok].second;
  }
  ll cost(int x, int t) {
    x = find(x, t);
    int ok = 0, ng = c[x].size();
    while (ng - ok > 1) {
      int mid = (ok + ng) / 2;
      if (c[x][mid].first <= t) {
        ok = mid;
      } else {
        ng = mid;
      }
    }
    return c[x][ok].second;
  }
  const int INF = 1 << 25;
  int V_NUM, now;
  vector<int> par, rank, tim;
  vector<vector<pair<int, int>>> num;
  vector<vector<pair<ll, ll>>> c;
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int N, M;
  cin >> N >> M;
  for (int i = 0; i < N; ++i) cin >> X[i];
  pair<ll, pair<int, int>> edges[M + 1];
  for (int i = 1; i <= M; ++i) {
    cin >> edges[i].second.first >> edges[i].second.second >> edges[i].first;
    --edges[i].second.first, --edges[i].second.second;
  }
  sort(edges + 1, edges + M + 1);
  persistentUF uf(N);
  for (int t = 1; t <= M; ++t) {
    uf.unite(edges[t].second.first, edges[t].second.second);
  }
  int ans = 0;
  bool ok[N];
  fill(ok, ok + N, false);
  set<int> ng;
  for (int i = 0; i < N; ++i) {
    ng.insert(i);
  }
  for (int t = M; t > 0; --t) {
    if (ok[edges[t].second.first]) continue;
    if (edges[t].first > uf.cost(edges[t].second.first, t)) {
      ++ans;
    } else {
      vector<int> v;
      for (int i : ng) {
        if (uf.same(i, edges[t].second.first, t)) {
          ok[i] = true;
          v.push_back(i);
        }
      }
      for (int i : v) ng.erase(i);
    }
  }
  cout << ans << endl;
  return 0;
}
