#include <bits/stdc++.h>
class UnionFindTree {
  const int size_m;
  mutable std::vector<int> parent_m;
  std::vector<int> card_m;

 public:
  UnionFindTree(int size);

 private:
  bool isValidIndex(int i) const;

 public:
  int rootOf(int i) const;
  bool isSame(int i, int j) const;
  void unite(int i, int j);
  int size() const;
  int cardinalityOf(int i) const;
  std::vector<std::vector<int>> toGroups() const;
};
class WeightedUnionFindTree {
  const int size_m;
  mutable std::vector<int> parent_m;
  mutable std::vector<uint64_t> diff_m;
  std::vector<int> card_m;

 public:
  WeightedUnionFindTree(int size);

 private:
  bool isValidIndex(int i) const;

 public:
  int rootOf(int i) const;
  bool isSame(int i, int j) const;
  int64_t query(int i, int j) const;
  bool unite(int i, int j, int64_t diff);

 private:
  int64_t weight(int i) const;

 public:
  int size() const;
};
UnionFindTree::UnionFindTree(int size)
    : size_m(size), parent_m(size), card_m(size, 1) {
  for (int i = 0; i < size; ++i) {
    parent_m[i] = i;
  }
}
bool UnionFindTree::isValidIndex(int i) const { return i >= 0 && i < size(); }
int UnionFindTree::rootOf(int i) const {
  assert(isValidIndex(i));
  if (parent_m[i] == i) return i;
  return parent_m[i] = rootOf(parent_m[i]);
}
bool UnionFindTree::isSame(int i, int j) const {
  assert(isValidIndex(i) && isValidIndex(j));
  int ri = rootOf(i);
  int rj = rootOf(j);
  return ri == rj;
}
void UnionFindTree::unite(int i, int j) {
  assert(isValidIndex(i) && isValidIndex(j));
  int ri = rootOf(i);
  int rj = rootOf(j);
  if (ri == rj) return;
  if (card_m[ri] < card_m[rj]) {
    std::swap(ri, rj);
  }
  parent_m[rj] = ri;
  card_m[ri] += card_m[rj];
}
int UnionFindTree::size() const { return size_m; }
int UnionFindTree::cardinalityOf(int i) const {
  assert(isValidIndex(i));
  int ri = rootOf(i);
  return card_m[ri];
}
std::vector<std::vector<int>> UnionFindTree::toGroups() const {
  std::vector<std::vector<int>> groups(size_m);
  for (int i = 0; i < size_m; ++i) {
    int ri = rootOf(i);
    groups[ri].push_back(i);
  }
  std::vector<std::vector<int>> ret;
  for (int i = 0; i < size_m; ++i) {
    if (groups[i].empty()) continue;
    ret.push_back(groups[i]);
  }
  return ret;
}
WeightedUnionFindTree::WeightedUnionFindTree(int size)
    : size_m(size), parent_m(size), diff_m(size), card_m(size, 1) {
  for (int i = 0; i < size; ++i) {
    parent_m[i] = i;
  }
}
bool WeightedUnionFindTree::isValidIndex(int i) const {
  return i >= 0 && i < size();
}
int WeightedUnionFindTree::rootOf(int i) const {
  assert(isValidIndex(i));
  if (parent_m[i] == i) return i;
  diff_m[i] += weight(parent_m[i]);
  return parent_m[i] = rootOf(parent_m[i]);
}
bool WeightedUnionFindTree::isSame(int i, int j) const {
  assert(isValidIndex(i) && isValidIndex(j));
  return rootOf(i) == rootOf(j);
}
int64_t WeightedUnionFindTree::query(int i, int j) const {
  assert(isValidIndex(i) && isValidIndex(j));
  return weight(j) - weight(i);
}
bool WeightedUnionFindTree::unite(int i, int j, int64_t diff) {
  assert(isValidIndex(i) && isValidIndex(j));
  int64_t diff_roots = diff + weight(i) - weight(j);
  int ri = rootOf(i);
  int rj = rootOf(j);
  if (ri == rj) return false;
  if (card_m[ri] < card_m[rj]) {
    std::swap(ri, rj);
    diff_roots = -diff_roots;
  }
  parent_m[rj] = ri;
  card_m[ri] += card_m[rj];
  diff_m[rj] = diff_roots;
  return true;
}
int64_t WeightedUnionFindTree::weight(int i) const {
  rootOf(i);
  return diff_m[i];
}
int WeightedUnionFindTree::size() const { return size_m; }
using namespace std;
using uint = uint32_t;
using LL = int64_t;
using ULL = uint64_t;
using PP = pair<LL, LL>;
template <typename T>
using PriorityQ = priority_queue<T, vector<T>, greater<T>>;
const int INF = 0x3FFFFFFF;
const LL INFLL = 0x3FFFFFFF3FFFFFFF;
const double INFD = 1.0e+308;
const double EPS = 1.0e-9;
void YesNo(bool b) { cout << (b ? "Yes" : "No") << endl; }
void YESNO(bool b) { cout << (b ? "YES" : "NO") << endl; }
template <class T, class U>
istream& operator>>(istream& ist, pair<T, U>& right) {
  return ist >> right.first >> right.second;
}
template <class T, class U>
ostream& operator<<(ostream& ost, const pair<T, U>& right) {
  return ost << right.first << ' ' << right.second;
}
template <class T, class TCompatible, size_t N>
void Fill(T (&dest)[N], const TCompatible& val) {
  fill(dest, dest + N, val);
}
template <class T, class TCompatible, size_t M, size_t N>
void Fill(T (&dest)[M][N], const TCompatible& val) {
  for (int i = 0; i < M; ++i) Fill(dest[i], val);
}
template <class T>
T Next() {
  T buf;
  cin >> buf;
  return buf;
}
istream& Ignore(istream& ist) {
  string s;
  ist >> s;
  return ist;
}
bool Inside(int i, int j, int h, int w) {
  return i >= 0 && i < h && j >= 0 && j < w;
}
istream& operator>>(istream& ist, __int128& val) {
  LL tmp;
  ist >> tmp;
  val = tmp;
  return ist;
}
ostream& operator<<(ostream& ost, __int128 val) {
  LL tmp = val;
  ost << tmp;
  return ost;
}
int N, M;
LL X[100000];
pair<LL, PP> E[100000];
vector<int> G[100000];
vector<int> cand;
int ans;
bool used[100000];
void rec(int j, LL c) {
  if (used[j]) return;
  used[j] = true;
  if (E[j].first <= c) ++ans;
  int a = E[j].second.first;
  int b = E[j].second.second;
  for (int nj : G[a]) rec(nj, c);
  for (int nj : G[b]) rec(nj, c);
}
void sub() {
  reverse(cand.begin(), cand.end());
  for (int j : cand) {
    rec(j, E[j].first);
  }
}
void pre() {
  UnionFindTree uf(N);
  for (LL j = (0), j_max_ = (M); j < j_max_; ++j) {
    LL c = E[j].first;
    PP e = E[j].second;
    int from = e.first;
    int to = e.second;
    if (uf.isSame(from, to)) continue;
    LL nw = X[uf.rootOf(from)] + X[uf.rootOf(to)];
    uf.unite(from, to);
    X[uf.rootOf(from)] = nw;
    if (c <= nw) {
      cand.push_back(j);
    }
  }
}
int main() {
  cin >> N >> M;
  for (LL i = (0), i_max_ = (N); i < i_max_; ++i) cin >> X[i];
  for (LL j = (0), j_max_ = (M); j < j_max_; ++j) {
    int a, b, c;
    cin >> a >> b >> c;
    --a;
    --b;
    E[j] = {c, PP(a, b)};
  }
  sort(E, E + M);
  for (LL j = (0), j_max_ = (M); j < j_max_; ++j) {
    int a = E[j].second.first;
    int b = E[j].second.second;
    G[a].push_back(j);
    G[b].push_back(j);
  }
  pre();
  sub();
  cout << M - ans << endl;
  return 0;
}
