#include <bits/stdc++.h>
using namespace std;
template <typename T>
class graph {
 public:
  struct edge {
    int from;
    int to;
    T cost;
  };
  static bool lt(edge e1, edge e2) { return e1.cost < e2.cost; }
  vector<edge> edges;
  vector<vector<int> > g;
  vector<int> visited;
  int n;
  graph(int n) : n(n) {
    g.resize(n);
    visited.resize(n, -1);
  }
  virtual void add(int from, int to, T cost = 0) {
    assert(0 <= from && from < n && 0 <= to && to < n);
    g[from].push_back(edges.size());
    g[to].push_back(edges.size());
    edges.push_back({from, to, cost});
  }
};
template <typename T>
class undigraph : public graph<T> {
 public:
  using graph<T>::edges;
  using graph<T>::g;
  using graph<T>::n;
  undigraph(int n) : graph<T>(n) {}
  void add(int from, int to, T cost = 1) {
    assert(0 <= from && from < n && 0 <= to && to < n);
    g[from].push_back(edges.size());
    g[to].push_back(edges.size());
    edges.push_back({from, to, cost});
  }
};
class UnionFind {
 private:
  std::vector<int> par;
  std::vector<int> rnk;
  std::vector<long long> wei;

 public:
  std::vector<long long> cap;
  UnionFind(int n, long long *x) : par(n), rnk(n), wei(n), cap(n) {
    for (int i = 0; i < n; i++) {
      par[i] = i;
      rnk[i] = 0;
      wei[i] = x[i];
      cap[i] = 0;
    }
  }
  int find(int x) {
    if (par[x] == x)
      return x;
    else
      return find(par[x]);
  }
  long long weight(int x) { return wei[find(x)]; }
  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return;
    if (rnk[x] < rnk[y]) swap(x, y);
    par[y] = x;
    if (rnk[x] == rnk[y]) rnk[x]++;
    wei[x] += wei[y];
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int capfind(int x) {
    if (x == par[x]) return cap[x] ? x : -1;
    int y = capfind(par[x]);
    if (y != -1) return y;
    return cap[x] ? x : -1;
  }
};
int n, m, acm = 0;
bool visited[100000];
long long x[100000];
void solve(int f, long long cost, undigraph<long long> &g) {
  for (int i = (0); i < (g.g[f].size()); ++i) {
    if (visited[g.g[f][i]]) continue;
    visited[g.g[f][i]] = true;
    if (g.edges[g.g[f][i]].cost <= cost) {
      acm++;
      solve(g.edges[g.g[f][i]].from ^ g.edges[g.g[f][i]].to ^ f, cost, g);
    }
  }
}
int main() {
  cin >> n >> m;
  for (int i = (0); i < (m); ++i) visited[i] = false;
  undigraph<long long> g(n);
  for (int i = (0); i < (n); ++i) cin >> x[i];
  long long y;
  int a, b;
  for (int i = (0); i < (m); ++i) {
    cin >> a >> b >> y;
    a--;
    b--;
    g.add(a, b, y);
  }
  vector<int> index(m);
  iota(index.begin(), index.end(), 0);
  sort(index.begin(), index.end(),
       [&](int x, int y) { return g.edges[x].cost < g.edges[y].cost; });
  UnionFind un(n, x);
  for (int i = (0); i < (m); ++i) {
    un.unite(g.edges[index[i]].from, g.edges[index[i]].to);
    if (un.weight(g.edges[index[i]].from) >= g.edges[index[i]].cost) {
      un.cap[un.find(g.edges[index[i]].from)] = g.edges[index[i]].cost;
    }
  }
  for (int i = (0); i < (n); ++i) {
    int f = un.capfind(i);
    if (f != -1) solve(f, un.cap[f], g);
  }
  cout << m - acm << endl;
  return 0;
}
