// vvvvvvvvvvvv TEMPLATE vvvvvvvvvvvv
#include <bits/stdc++.h>
using namespace std; using ll = long long; using P = pair<ll, ll>;
const ll linf = 1e18; const double eps = 1e-12, pi = acos(-1);
#define FOR(i,a,b) for (ll i=(a),__last_##i=(b);i<__last_##i;i++)
#define RFOR(i,a,b) for (ll i=(b)-1,__last_##i=(a);i>=__last_##i;i--)
#define REP(i,n) FOR(i,0,n)
#define RREP(i,n) RFOR(i,0,n)
#define __GET_MACRO3(_1, _2, _3, NAME, ...) NAME
#define each(i,a) for (auto&& i : a)
#define rep(...) __GET_MACRO3(__VA_ARGS__, FOR, REP)(__VA_ARGS__)
#define rrep(...) __GET_MACRO3(__VA_ARGS__, RFOR, RREP)(__VA_ARGS__)
#define pb push_back
#define eb emplace_back
#define all(a) begin(a),end(a)
#define chmin(x,v) x = min(x, v)
#define chmax(x,v) x = max(x, v)
#define min(x,y) (x < y ? x : y)
#define max(x,y) (x < y ? y : x)
template<typename Head> void out(Head h) { cout << h << endl; } template<typename Head, typename... Tail>void out(Head h, Tail... t) { cout << h << " "; out(t...); }
template<typename T> istream& operator>>(istream& is, vector<T>& v) { each(x,v) is >> x; return is; }
template<typename T> ostream& operator<<(ostream& os, const vector<T>& v) { rep(i,v.size()) { if (i) os << " "; os << v[i]; } return os; }
ostream& operator<<(ostream& os, const vector<string>& v) { rep(i,v.size()) { if (i) os << endl; os << v[i]; } return os; }
template<typename T> ostream& operator<<(ostream& os, const vector<vector<T>>& v) { rep(i,v.size()) { if (i) os << endl; os << v[i]; } return os; }
template<typename T1, typename T2> ostream& operator<<(ostream& os, const pair<T1, T2>& p) { return os << "(" << p.first << ", " << p.second << ")"; }
struct yes_no : std::numpunct<char> { string_type do_truename() const { return "Yes"; } string_type do_falsename() const { return "No"; } };
void solve(); int main() {
  ios::sync_with_stdio(false); cin.tie(0); locale loc(locale(), new yes_no); cout.imbue(loc); cout << fixed << setprecision(10) << boolalpha;
  solve();
}
// ^^^^^^^^^^^^ TEMPLATE ^^^^^^^^^^^^

class RollbackableUnionFind {
  struct Changes {
    bool is_changed;
    ll u, v, parv, wu, hu, hv;
  };
  stack<Changes> s;
  vector<ll> par, h, w;
public:
  RollbackableUnionFind(vector<ll> w) : par(w.size(), 0), h(w.size(), 0), w(w) {
    rep(i, w.size()) par[i] = i;
  }
  void unite(ll u, ll v) {
    u = root(u), v = root(v);
    if (u == v) {
      s.push({false});
      return;
    }
    if (h[u] < h[v]) {
      s.push({true, v, u, par[u], w[v], h[v], h[u]});
      par[u] = v;
      w[v] += w[u];
    }
    else {
      s.push({true, u, v, par[v], w[u], h[u], h[v]});
      par[v] = u;
      w[u] += w[v];
    }
    if (h[u] == h[v]) ++h[u];
  }
  ll sum(ll v) const {
    return w[root(v)];
  }
  bool isUnited(ll u, ll v) const {
    return root(u) == root(v);
  }
  ll root(ll v) const {
    if (par[v] == v) return v;
    return root(par[v]);
  }
  void rollback() {
    assert(s.size() > 0);
    Changes c = s.top();
    if (!c.is_changed) return;
    par[c.v] = c.parv;
    w[c.u] = c.wu;
    h[c.u] = c.hu;
    h[c.v] = c.hv;
    s.pop();
  }
};


struct Edge {
  ll a, b, c;
};
bool operator<(const Edge& e1, const Edge& e2) {
  return e1.c < e2.c;
}

void solve() {
  ll n, m; cin >> n >> m;
  vector<ll> w(n); cin >> w;
  vector<Edge> edges;
  rep(i, m) {
    ll a, b, c; cin >> a >> b >> c; --a, --b;
    edges.pb({a, b, c});
  }
  sort(all(edges));
  vector<vector<P>> G(n);
  each(e, edges) {
    G[e.a].eb(e.b, e.c);
    G[e.b].eb(e.a, e.c);
  }
  vector<bool> ok(n, false);
  function<void(ll,ll)> dfs = [&](ll v, ll th) {
    ok[v] = true;
    each(e, G[v]) {
      if (e.second > th) continue;
      if (ok[e.first]) continue;
      dfs(e.first, th);
    }
  };
  RollbackableUnionFind uf(w);
  vector<bool> f;
  each(e, edges) {
    uf.unite(e.a, e.b);
    f.pb(e.c > uf.sum(e.a));
  }
  ll ans = 0;
  rrep(i, m) {
    // cout << i << endl;
    Edge& e = edges[i];
    if (ok[e.a]) continue;
    // assert(uf.isUnited(e.a, e.b));
    if (f[i]) {
      ++ans;
    }
    else {
      dfs(e.a, e.c);
    }
    // uf.rollback();
  }
  cout << ans << endl;
}


Measured memory_bytes: 25196