#include <bits/stdc++.h>
using namespace std;
struct Graph {
  int n;
  vector<vector<int>> g;
  Graph(int n) : n(n) { g.resize(n); }
  void init(int n_) {
    n = n_;
    g.resize(n_);
  }
  void add_edge(int from, int to) { g[from].push_back(to); }
};
Graph g(0);
template <typename G>
struct UnionFind {
  using F2 = function<G(G, G)>;
  using F1 = function<G(G)>;
  const F2 f;
  const F1 inverse;
  vector<int> par, rank;
  vector<G> dat;
  vector<int> last;
  UnionFind(
      int n, const F2 f = [](G a, G b) { return a + b; },
      F1 inv = [](G a) { return -a; })
      : f(f), inverse(inv) {
    par.resize(n);
    rank.resize(n);
    dat.assign(n, 1);
    for (int i = 0; i < n; i++) {
      par[i] = i;
      rank[i] = 0;
    }
  }
  int find(int i) {
    if (i == par[i]) return i;
    return find(par[i]);
  }
  bool same(int i, int j) { return find(i) == find(j); }
  void unite(int i, int j) {
    i = find(i), j = find(j);
    if (i == j) return;
    if (rank[i] < rank[j]) {
      par[i] = j;
      dat[j] = f(dat[i], dat[j]);
      last.push_back(i);
      g.add_edge(j, i);
    } else {
      par[j] = i;
      dat[i] = f(dat[i], dat[j]);
      if (rank[i] == rank[j]) rank[i]++;
      last.push_back(j);
      g.add_edge(i, j);
    }
  }
  G query(int i) { return dat[find(i)]; }
  void undo() {
    if ((int)last.size() == 0) return;
    int i = *(--last.end());
    int j = find(i);
    par[i] = i;
    dat[j] = f(dat[j], inverse(dat[i]));
    last.pop_back();
  }
};
int main() {
  int n, m;
  cin >> n >> m;
  g.init(n);
  UnionFind<long long> uf(n);
  for (int i = 0; i < n; i++) {
    long long x;
    cin >> x;
    uf.dat[i] = x;
  }
  pair<long long, pair<int, int>> p[100002];
  for (int i = 0; i < m; i++) {
    int a, b;
    long long y;
    cin >> a >> b >> y;
    a--;
    b--;
    p[i] = pair<long long, pair<int, int>>(y, pair<int, int>(a, b));
  }
  sort(p, p + m);
  vector<int> v;
  for (int i = 0; i < m; i++) {
    int a = p[i].second.first, b = p[i].second.second;
    if (uf.find(a) != uf.find(b)) {
      uf.unite(a, b);
      v.push_back(i);
    }
  }
  bool used[100002]{0};
  bool del[100002]{0};
  int ans = 0;
  for (int i = m - 1; i >= 0; i--) {
    int a = p[i].second.first;
    if (used[a]) continue;
    if (uf.query(a) < p[i].first)
      ans++;
    else {
      queue<int> que;
      que.push(uf.find(a));
      while (que.size()) {
        int u = que.front();
        que.pop();
        used[u] = true;
        for (int v : g.g[u]) {
          if (del[v]) continue;
          que.push(v);
        }
      }
    }
    if (*(--v.end()) == i) {
      del[*(--uf.last.end())] = true;
      uf.undo();
      v.pop_back();
    }
  }
  cout << ans << endl;
}
