#include <bits/stdc++.h>
using namespace std;
using Int = long long;
using _int = int;
using ll = long long;
using Double = long double;
const Int INF = (1LL << 60) + 1e9;
const Int mod = (1e9) + 7;
const Double EPS = 1e-8;
const Double PI = 6.0 * asin((Double)0.5);
using P = pair<Int, Int>;
template <class T>
T Max(T& a, T b) {
  return a = max(a, b);
}
template <class T>
T Min(T& a, T b) {
  return a = min(a, b);
}
template <class T1, class T2>
ostream& operator<<(ostream& o, pair<T1, T2> p) {
  return o << "(" << p.first << "," << p.second << ")";
}
template <class T1, class T2, class T3>
ostream& operator<<(ostream& o, tuple<T1, T2, T3> t) {
  return o << "(" << get<0>(t) << "," << get<1>(t) << "," << get<2>(t) << ")";
}
template <class T1, class T2>
istream& operator>>(istream& i, pair<T1, T2>& p) {
  return i >> p.first >> p.second;
}
template <class T>
ostream& operator<<(ostream& o, vector<T> a) {
  Int i = 0;
  for (T t : a) o << (i++ ? " " : "") << t;
  return o;
}
template <class T>
istream& operator>>(istream& i, vector<T>& a) {
  for (T& t : a) i >> t;
  return i;
}
class TreeParent {
 public:
  Int V;
  Int root;
  vector<vector<Int> > G;
  vector<Int> parent;
  Int ok;
  TreeParent() : V(-1){};
  TreeParent(Int V, Int root = 0) : V(V), root(root), G(V), parent(V), ok(0) {}
  TreeParent(vector<vector<Int> > G, Int root = 0)
      : V(G.size()), root(root), G(G), parent(V), ok(0) {}
  void resize(Int n) { *this = TreeParent(n); }
  void add_edge(Int a, Int b) {
    ok = false;
    assert(a < V && b < V);
    assert(a >= 0 && b >= 0);
    G[a].push_back(b);
    G[b].push_back(a);
  }
  void build(Int root = -1) {
    ok = 1;
    if (root != -1) this->root = root;
    function<void(Int, Int)> dfs = [&](Int pos, Int pre) {
      parent[pos] = pre;
      for (Int to : G[pos])
        if (to != pre) dfs(to, pos);
    };
    dfs(this->root, -1);
  }
  Int get(Int u) {
    assert(ok);
    assert(0 <= u && u < V);
    return parent[u];
  }
};
class UF {
 public:
  Int V;
  vector<Int> par, rnk, sz;
  UF() {}
  UF(Int V) : V(V), par(V), rnk(V, 0), sz(V, 1) {
    for (Int i = 0; i < V; i++) par[i] = i;
  }
  Int find(Int x) {
    assert(x < V);
    if (par[x] == x) return x;
    return par[x] = find(par[x]);
  }
  void unite(Int x, Int y) {
    x = find(x), y = find(y);
    if (x == y) return;
    if (rnk[x] < rnk[y])
      par[x] = y, sz[y] += sz[x];
    else {
      par[y] = x;
      sz[x] += sz[y];
      if (rnk[x] == rnk[y]) rnk[x]++;
    }
  }
  bool same(Int x, Int y) { return find(x) == find(y); }
  Int size(Int x) { return sz[find(x)]; }
};
Int N, M;
vector<Int> w;
using T = tuple<Int, Int, Int>;
vector<Int> kurasukal(vector<T>& edge) {
  sort(edge.begin(), edge.end());
  UF uf(N);
  vector<Int> used(M);
  for (Int i = 0; i < M; i++) {
    Int c, a, b;
    tie(c, a, b) = edge[i];
    if (uf.same(a, b)) continue;
    uf.unite(a, b);
    used[i] = 1;
  }
  return used;
}
vector<Int> calcDepth(vector<vector<P> >& G) {
  vector<Int> depth(N);
  function<void(Int, Int, Int)> dfs = [&](Int pos, Int pre, Int dep) {
    depth[pos] = dep;
    for (auto p : G[pos]) {
      Int to = p.first;
      if (to != pre) dfs(to, pos, dep + 1);
    }
  };
  dfs(0, -1, 0);
  return depth;
}
Int solve(vector<T>& edge) {
  vector<Int> used = kurasukal(edge);
  vector<vector<P> > G(N);
  TreeParent tp(N);
  vector<map<Int, Int> > mG(N);
  for (Int i = 0; i < M; i++) {
    if (used[i] == 0) continue;
    Int c, a, b;
    tie(c, a, b) = edge[i];
    G[a].push_back(P(b, c));
    G[b].push_back(P(a, c));
    mG[a][b] = c;
    mG[b][a] = c;
    tp.add_edge(a, b);
  }
  vector<Int> depth = calcDepth(G);
  tp.build(0);
  vector<P> ord(N);
  for (Int i = 0; i < N; i++) ord[i] = P(depth[i], i);
  sort(ord.begin(), ord.end(), greater<P>());
  UF uf(N);
  Int sum = 0;
  for (Int i = 0; i < N; i++) sum += w[i];
  for (Int i = 0; i < N; i++) uf.sz[i] = w[i];
  for (Int i = 0; i < N; i++) {
    Int x = ord[i].second;
    Int par = tp.get(x);
    Int cost = mG[x][par];
    if (cost <= sum)
      uf.unite(x, par);
    else
      sum -= uf.size(x);
  }
  Int ans = 0;
  for (Int i = 0; i < M; i++) {
    Int c, a, b;
    tie(c, a, b) = edge[i];
    if (!(uf.same(a, b) && uf.size(a) >= c)) ans++;
  }
  return ans;
}
signed main() {
  srand((unsigned)time(NULL));
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);
  cin >> N >> M;
  w.resize(N);
  cin >> w;
  vector<T> edge(M);
  for (Int i = 0; i < M; i++) {
    Int a, b, c;
    cin >> a >> b >> c;
    a--, b--;
    edge[i] = T(c, a, b);
  }
  Int ans = solve(edge);
  cout << ans << endl;
  return 0;
}
