#include <bits/stdc++.h>
using namespace std;
template <class S, class T>
ostream& operator<<(ostream& o, const pair<S, T>& p) {
  return o << "(" << p.first << "," << p.second << ")";
}
template <class T>
ostream& operator<<(ostream& o, const vector<T>& vc) {
  o << "{";
  for (const T& v : vc) o << v << ",";
  o << "}";
  return o;
}
using ll = long long;
template <class T>
using V = vector<T>;
template <class T>
using VV = vector<vector<T>>;
class persistentUF {
 public:
  const static int MAX_N = 20;
  unordered_map<int, int> par[MAX_N];
  map<int, ll> sz[MAX_N];
  int rank[MAX_N];
  int fin[MAX_N];
  int idx;
  persistentUF() { init(); }
  void init() {
    idx = 0;
    for (int i = 0; i < (int)(MAX_N); i++)
      par[i][0] = i, rank[i] = 1, fin[i] = 0;
  }
  persistentUF(int n) { init(n); }
  void init(int n) {
    idx = 0;
    for (int i = 0; i < (int)(n); i++) par[i][0] = i, rank[i] = 1, fin[i] = 0;
  }
  int find(int x, int t) {
    if (t >= fin[x] && par[x][fin[x]] != x) return find(par[x][fin[x]], t);
    return x;
  }
  ll getsize(int x, int t) {
    x = find(x, t);
    auto it = sz[x].upper_bound(t);
    it--;
    return it->second;
  }
  void unite(int x, int y) {
    x = find(x, idx);
    y = find(y, idx);
    ll szx = getsize(x, idx);
    ll szy = getsize(y, idx);
    idx++;
    if (x == y) return;
    if (rank[x] < rank[y])
      par[x][idx] = y, fin[x] = idx, sz[y][idx] = szx + szy;
    else {
      par[y][idx] = x, fin[y] = idx, sz[x][idx] = szx + szy;
      if (rank[x] == rank[y]) rank[x]++;
    }
  }
  bool same(int x, int y, int t) { return find(x, t) == find(y, t); }
};
int N, M;
V<int> X, Y, A, B;
int main() {
  cin >> N >> M;
  X.resize(N);
  Y.resize(M);
  A.resize(M);
  B.resize(M);
  for (int i = 0; i < (int)(N); i++) cin >> X[i];
  {
    using P = pair<int, int>;
    using PP = pair<int, P>;
    V<PP> es;
    for (int i = 0; i < (int)(M); i++) {
      int a, b, c;
      cin >> a >> b >> c;
      a--, b--;
      es.push_back(PP(c, P(a, b)));
    }
    sort(es.begin(), es.end());
    for (int i = 0; i < (int)(M); i++)
      A[i] = es[i].second.first, B[i] = es[i].second.second, Y[i] = es[i].first;
  }
  persistentUF UF(N);
  for (int i = 0; i < (int)(N); i++) UF.sz[i][0] = X[i];
  for (int t = 0; t < (int)(M); t++) {
    UF.unite(A[t], B[t]);
  }
  int erasenum = 0;
  V<bool> ok(N);
  for (int t = M - 1; t >= 0; t--) {
    if (ok[A[t]]) continue;
    if (UF.getsize(A[t], t + 1) < Y[t]) {
      erasenum++;
    } else {
      for (int i = 0; i < (int)(N); i++)
        if (!ok[i] && UF.same(i, A[t], t + 1)) ok[i] = true;
    }
  }
  cout << erasenum << endl;
}
