#include <bits/stdc++.h>
using namespace std;
template <class T>
void UNIQUE(T &v) {
  v.erase(unique(v.begin(), v.end()), v.end());
}
struct range {
  struct Iter {
    int v, step;
    Iter &operator++() {
      v += step;
      return *this;
    }
    bool operator!=(Iter &itr) { return v < itr.v; }
    int &operator*() { return v; }
  };
  Iter i, n;
  range(int i, int n, int step) : i({i, step}), n({n, step}) {}
  range(int i, int n) : range(i, n, 1) {}
  range(int n) : range(0, n) {}
  Iter &begin() { return i; }
  Iter &end() { return n; }
};
struct rrange {
  struct Iter {
    int v, step;
    Iter &operator++() {
      v -= step;
      return *this;
    }
    bool operator!=(Iter &itr) { return v > itr.v; }
    int &operator*() { return v; }
  };
  Iter i, n;
  rrange(int i, int n, int step) : i({i - 1, step}), n({n - 1, step}) {}
  rrange(int i, int n) : rrange(i, n, 1) {}
  rrange(int n) : rrange(0, n) {}
  Iter &begin() { return n; }
  Iter &end() { return i; }
};
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p) {
  return is >> p.first >> p.second;
}
template <typename T1>
istream &operator>>(istream &is, tuple<T1> &t) {
  return is >> get<0>(t);
}
template <typename T1, typename T2>
istream &operator>>(istream &is, tuple<T1, T2> &t) {
  return is >> get<0>(t) >> get<1>(t);
}
template <typename T1, typename T2, typename T3>
istream &operator>>(istream &is, tuple<T1, T2, T3> &t) {
  return is >> get<0>(t) >> get<1>(t) >> get<2>(t);
}
template <typename T1, typename T2, typename T3, typename T4>
istream &operator>>(istream &is, tuple<T1, T2, T3, T4> &t) {
  return is >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
}
template <typename T>
istream &operator>>(istream &is, vector<T> &as) {
  for (int i : range(as.size())) is >> as[i];
  return is;
}
template <typename T>
ostream &operator<<(ostream &os, const set<T> &ss) {
  for (auto a : ss) {
    if (a != ss.begin()) os << " ";
    os << a;
  }
  return os;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p) {
  return os << p.first << " " << p.second;
}
template <typename K, typename V>
ostream &operator<<(ostream &os, const map<K, V> &m) {
  bool isF = true;
  for (auto &p : m) {
    if (!isF) os << endl;
    os << p;
    isF = false;
  }
  return os;
}
template <typename T1>
ostream &operator<<(ostream &os, const tuple<T1> &t) {
  return os << get<0>(t);
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const tuple<T1, T2> &t) {
  return os << get<0>(t) << " " << get<1>(t);
}
template <typename T1, typename T2, typename T3>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3> &t) {
  return os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t);
}
template <typename T1, typename T2, typename T3, typename T4>
ostream &operator<<(ostream &os, const tuple<T1, T2, T3, T4> &t) {
  return os << get<0>(t) << " " << get<1>(t) << " " << get<2>(t) << " "
            << get<3>(t);
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &as) {
  for (int i : range(as.size())) {
    if (i != 0) os << " ";
    os << as[i];
  }
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<vector<T>> &as) {
  for (int i : range(as.size())) {
    if (i != 0) os << endl;
    os << as[i];
  }
  return os;
}
template <typename T>
inline T INF() {
  assert(false);
};
template <>
inline int INF<int>() {
  return 1 << 28;
};
template <>
inline long long INF<long long>() {
  return 1LL << 60;
};
template <>
inline double INF<double>() {
  return 1e16;
};
template <>
inline long double INF<long double>() {
  return 1e16;
};
template <class T>
inline T EPS() {
  assert(false);
};
template <>
inline int EPS<int>() {
  return 1;
};
template <>
inline long long EPS<long long>() {
  return 1LL;
};
template <>
inline double EPS<double>() {
  return 1e-12;
};
template <>
inline long double EPS<long double>() {
  return 1e-12;
};
template <typename T>
inline T upper_pow2(T n) {
  T res = 1;
  while (res < n) res <<= 1;
  return res;
}
template <typename T>
inline T msb(T n) {
  int d = 62;
  while ((1LL << d) > n) d--;
  return d;
}
template <typename T, typename U>
T pmod(T v, U M) {
  return (v % M + M) % M;
}
long long mod = 998244353;
struct mint {
  long long x, mod;
  mint(long long x, long long mod = 998244353)
      : x((x % mod + mod) % mod), mod(mod) {}
  mint() : mint(0) {}
  mint operator+=(const mint &a) {
    if ((x += a.x) >= mod) x -= mod;
    return *this;
  }
  mint operator-=(const mint &a) {
    if ((x += mod - a.x) >= mod) x -= mod;
    return *this;
  }
  mint operator*=(const mint &a) {
    (x *= a.x) %= mod;
    return *this;
  }
  mint operator+(const mint &a) const { return mint(*this) += a; }
  mint operator-(const mint &a) const { return mint(*this) -= a; }
  bool operator==(const mint &a) const { return x == a.x; }
  mint operator*(const mint &a) const { return mint(*this) *= a; }
  mint pow(long long N) {
    mint r(1), x = *this;
    while (N) {
      if (N & 1) r *= x;
      N /= 2;
      x *= x;
    }
    return r;
  }
  mint minv() { return pow(mod - 2); }
};
istream &operator>>(istream &is, mint &p) { return is >> p.x; }
ostream &operator<<(ostream &os, mint m) {
  os << m.x;
  return os;
}
struct UnionFind {
  vector<int> par, rank, ss;
  int size;
  vector<int> nsum, ec, oec;
  UnionFind(int n) : size(n) {
    par = vector<int>(n);
    iota(par.begin(), par.end(), 0);
    rank = vector<int>(n);
    ss = vector<int>(n, 1);
    ec = vector<int>(n);
    oec = vector<int>(n);
  }
  int root(int x) { return par[x] = par[x] == x ? x : root(par[x]); }
  bool same(int x, int y) { return root(x) == root(y); }
  void unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x == y) return;
    if (rank[x] > rank[y]) swap(x, y);
    par[x] = y;
    ss[y] += ss[x];
    nsum[y] += nsum[x];
    ec[y] += ec[x];
    oec[y] += oec[x];
    if (rank[x] == rank[y]) rank[x]++;
    size--;
  }
  int getS(int x) { return ss[root(x)]; }
};
void run() {
  int N, M;
  cin >> N >> M;
  vector<int> vs(N);
  cin >> vs;
  vector<tuple<int, int, int>> es(M);
  for (int i : range(M)) {
    int v, w, d;
    cin >> v >> w >> d;
    v--;
    w--;
    es[i] = make_tuple(d, v, w);
  }
  sort(es.begin(), es.end());
  UnionFind uf(N);
  uf.nsum = vs;
  for (int i : range(M)) {
    int d, v, w;
    tie(d, v, w) = es[i];
    uf.unite(v, w);
    uf.ec[uf.root(v)]++;
    if (uf.nsum[uf.root(v)] >= d) {
      uf.oec[uf.root(v)] = uf.ec[uf.root(v)];
    }
  }
  int res = 0;
  for (int i : range(N))
    if (uf.root(i) == i) {
      res += uf.oec[i];
    }
  cout << M - res << endl;
}
int main() {
  cout << fixed << setprecision(20);
  cin.tie(0);
  ios::sync_with_stdio(false);
  run();
  return 0;
}
