#include <bits/stdc++.h>
using namespace std;
template <class C>
int size(const C &c) {
  return c.size();
}
template <class T, class... U>
bool chmin(T &a, const U &...bs) {
  const T b(bs...);
  if (a <= b) return false;
  a = b;
  return true;
}
template <class T, class... U>
bool chmax(T &a, const U &...bs) {
  const T b(bs...);
  if (a >= b) return false;
  a = b;
  return true;
}
struct UnionFind {
  vector<int> par;
  vector<long long> weight;
  int n, cnt;
  UnionFind(const int &x = 0) { init(x); }
  void init(const int &x) {
    par.assign(cnt = n = x, -1);
    weight.assign(n, 0);
  }
  inline int find(const int &x) {
    return par[x] < 0 ? x : par[x] = find(par[x]);
  }
  inline bool same(const int &x, const int &y) { return find(x) == find(y); }
  inline bool unite(int x, int y) {
    if ((x = find(x)) == (y = find(y))) return false;
    --cnt;
    if (par[x] > par[y]) swap(x, y);
    par[x] += par[y];
    par[y] = x;
    weight[x] += weight[y];
    return true;
  }
  inline int count() const { return cnt; }
  inline int count(int x) { return -par[find(x)]; }
  inline long long getWeight(const int x) { return weight[find(x)]; }
};
namespace LinkCutTree {
struct Node {
  typedef Node *Ptr;
  Ptr ch[2];
  Ptr par;
  Node(long long v) : par(0), size(1) {
    ch[0] = ch[1] = 0;
    init(v);
  }
  pair<int, int> id;
  string name;
  long long val;
  bool reversed;
  inline void init(long long v) {
    reversed = false;
    val = sum = v;
  }
  inline void push() {
    if (reversed) {
      swap(ch[0], ch[1]);
      reversed = false;
      for (int i = (int)(0); i < (int)(2); ++i)
        if (ch[i]) ch[i]->reversed ^= true;
    }
  }
  inline void update() { push(); }
  int size;
  long long sum;
  inline int get_size() {
    expose();
    return size - (ch[0] ? ch[0]->size : 0);
  }
  inline int get_sum() {
    expose();
    return sum - (ch[0] ? ch[0]->sum : 0);
  }
  inline void remove_ch(Ptr p, int lr) {
    push();
    if (lr) ch[lr > 0] = 0;
    if (p) {
      size -= p->size;
      sum -= p->sum;
      p->par = 0;
      p->push();
    }
    update();
  }
  inline void add_ch(Ptr p, int lr) {
    push();
    if (p && p->par) p->par->remove_ch(p, p->state());
    if (p) {
      sum += p->sum;
    }
    if (lr) ch[lr > 0] = p;
    if (p) p->par = this;
    update();
  }
  inline int state() {
    if (par && par->ch[0] == this) return -1;
    if (par && par->ch[1] == this) return +1;
    return 0;
  }
  inline void rotate() {
    Ptr p = par, pp = p->par;
    if (pp) pp->push();
    p->push();
    push();
    int lr = state(), plr = p->state();
    Ptr c = ch[lr < 0];
    p->remove_ch(this, lr);
    p->add_ch(c, lr);
    add_ch(p, -lr);
    if (pp) pp->add_ch(this, plr);
  }
  inline void splay() {
    while (state()) {
      int s = state() * par->state();
      if (s) (s == 1 ? par : this)->rotate();
      rotate();
    }
    push();
  }
  inline Ptr expose() {
    Ptr res = 0;
    for (Ptr p = this; p; p = p->par) {
      p->splay();
      p->add_ch(res, 1);
      res = p;
    }
    splay();
    add_ch(ch[1], 0);
    return res;
  }
  inline void evert() {
    expose();
    reversed ^= true;
  }
  inline void cut() {
    expose();
    if (ch[0]) remove_ch(ch[0], -1);
  }
  inline void link_to(Ptr p) {
    p->expose();
    expose();
    p->add_ch(this, 0);
  }
  inline Ptr find_root() {
    expose();
    Ptr p = this;
    while (p->ch[0]) p = p->ch[0];
    p->expose();
    return p;
  }
  inline Ptr lca(Ptr u) {
    expose();
    Ptr res = u->expose();
    return par ? res : 0;
  }
};
};  // namespace LinkCutTree
bool solve() {
  int n, m;
  cin >> n >> m;
  UnionFind uf(n);
  UnionFind uf2(n);
  vector<tuple<int, int, int>> es;
  vector<long long> x(n);
  for (int i = (int)(0); i < (int)(n); ++i) cin >> x[i];
  for (int i = (int)(0); i < (int)(n); ++i) uf.weight[i] = x[i];
  for (int i = (int)(0); i < (int)(n); ++i) uf2.weight[i] = x[i];
  for (int i = (int)(0); i < (int)(m); ++i) {
    int a, b, y;
    cin >> a >> b >> y;
    --a;
    --b;
    es.emplace_back(y, a, b);
  }
  sort(begin(es), end(es));
  vector<tuple<int, int, int>> forest;
  vector<LinkCutTree::Node> lc;
  lc.reserve(n);
  for (int i = (int)(0); i < (int)(n); ++i) lc.emplace_back(x[i]);
  for (int i = (int)(0); i < (int)(m); ++i)
    if (uf.unite(get<1>(es[i]), get<2>(es[i]))) {
      const auto u = get<1>(es[i]), v = get<2>(es[i]);
      forest.emplace_back(es[i]);
      lc[u].evert();
      lc[v].evert();
      lc[u].link_to(&lc[v]);
    }
  reverse(begin(forest), end(forest));
  for (auto &e : forest) {
    const auto u = get<1>(e), v = get<2>(e);
    const auto y = get<0>(e);
    lc[u].evert();
    const long long sum = lc[u].get_sum();
    if (y > sum) {
      lc[u].evert();
      lc[v].cut();
    } else {
      uf2.unite(u, v);
    }
  }
  int res = m;
  for (auto &e : es) {
    const auto u = get<1>(e), v = get<2>(e);
    const auto y = get<0>(e);
    if (uf2.same(u, v) && uf2.getWeight(u) >= y) {
      --res;
    } else {
    }
  }
  cout << res << endl;
  return true;
}
signed main() {
  cin.tie(nullptr);
  ios_base::sync_with_stdio(false);
  cout << std::fixed << std::setprecision(10);
  solve();
  return 0;
}
