#include <bits/stdc++.h>
using namespace std;
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val) {
  std::fill((T *)array, (T *)(array + N), val);
}
pair<long long, long long> Dir[8] = {{0, 1}, {-1, 0}, {1, 0},  {0, -1},
                                     {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
struct segtree {
  int N, dat[2 * 300000];
  segtree() {}
  segtree(int n) {
    N = 1;
    while (N < n) N *= 2;
    for (int i = 0; i < 2 * N - 1; i++) dat[i] = 10000000000000000LL;
  }
  void update(int k, int a) {
    k += N - 1;
    dat[k] = a;
    while (k > 0) {
      k = (k - 1) / 2;
      dat[k] = min(dat[k * 2 + 1], dat[k * 2 + 2]);
    }
  }
  int query(int a, int b) { return query(a, b, 0, 0, N); }
  int query(int a, int b, int k, int l, int r) {
    if (r <= a || b <= l) return 10000000000000000LL;
    if (a <= l && r <= b) return dat[k];
    int m = (l + r) / 2;
    return min(query(a, b, k * 2 + 1, l, m), query(a, b, k * 2 + 2, m, r));
  }
};
struct Edge {
  int num;
  int from, to;
  long long w;
};
struct UnionFind_P {
 private:
  vector<int> data;
  vector<long long> sz;
  int root(int x) { return data[x] < 0 ? x : root(data[x]); }

 public:
  vector<vector<pair<int, int>>> tb;
  vector<vector<pair<int, long long>>> tsz;
  int s_cou = 0;
  UnionFind_P(int size)
      : tb(size, vector<pair<int, int>>(1)),
        data(size, -1),
        sz(size, 0),
        tsz(size, vector<pair<int, long long>>(1)) {
    for (int i = (0); (size) > i; i++) {
      tb[i][0] = {0, i};
    }
  }
  void Initsz(vector<long long> szarr) {
    for (int i = (0); (data.size()) > i; i++) {
      sz[i] = szarr[i];
      tsz[i][0] = {0, szarr[i]};
    }
  }
  bool unionSet(int x, int y) {
    x = root(x);
    y = root(y);
    s_cou++;
    if (x != y) {
      if (data[y] < data[x]) swap(x, y);
      data[x] += data[y];
      data[y] = x;
      tb[y].push_back({s_cou, x});
      sz[x] += sz[y];
      sz[y] = 0;
      tsz[x].push_back({s_cou, sz[x]});
    }
    return x != y;
  }
  int findroot(int u, int t) {
    auto itr = --upper_bound((tb[u]).begin(), (tb[u]).end(),
                             make_pair((t), (INT_MAX)));
    return itr->second == u ? u : findroot(itr->second, t);
  }
  int getsz(int u, int t) {
    int rt = findroot(u, t);
    auto itr = --upper_bound((tsz[rt]).begin(), (tsz[rt]).end(),
                             make_pair((t), (LLONG_MAX)));
    return itr->second;
  }
};
signed main(void) {
  int n, m;
  cin >> n >> m;
  vector<vector<Edge>> g(n);
  vector<pair<long long, pair<int, int>>> edges(m);
  vector<long long> X(n);
  UnionFind_P ufp(n);
  for (int i = (0); (n) > i; i++) {
    scanf("%lld", &X[i]);
  }
  ufp.Initsz(X);
  for (int i = (0); (m) > i; i++) {
    int a, b;
    long long c;
    scanf("%d %d %lld", &a, &b, &c);
    a--, b--;
    g[a].push_back({i, a, b, c});
    g[b].push_back({i, b, a, c});
    edges[i] = {c, {a, b}};
  }
  sort((edges).begin(), (edges).end());
  for (int i = (0); (m) > i; i++) {
    ufp.unionSet(edges[i].second.first, edges[i].second.second);
  }
  int ans = 0;
  vector<int> used(n), useded(m);
  function<void(int, long long)> dfs = [&](int cur, long long kyoyou) {
    used[cur] = 1;
    for (auto itr : g[cur]) {
      if (itr.w <= kyoyou) {
        if (useded[itr.num] == 0) {
          ans++;
          useded[itr.num] = 1;
        }
        int nex = itr.to;
        if (used[nex] == 0) {
          dfs(nex, kyoyou);
          used[nex] = 1;
        }
      }
    }
  };
  for (int v = (0); (n) > v; v++) {
    long long l = 0, r = m;
    while (r - l > 1) {
      long long mid = (l + r) / 2;
      long long sz = edges[mid - 1].first;
      long long realsz = ufp.getsz(v, mid);
      if (sz <= realsz) {
        l = mid;
      } else {
        r = mid;
      }
    }
    if (l == 0)
      dfs(v, 0);
    else
      dfs(v, edges[l - 1].first);
  }
  cout << m - ans << endl;
  return 0;
}
