#include <bits/stdc++.h>
using namespace std;
template <class T>
bool chmax(T &a, const T &b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
bool chmin(T &a, const T &b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class A, size_t N, class T>
void Fill(A (&a)[N], const T &v) {
  fill((T *)a, (T *)(a + N), v);
}
template <class T>
ostream &operator<<(ostream &os, const vector<T> &t) {
  os << "{";
  for (int i = 0; i < (t.size()); i++) {
    os << t[i] << ",";
  }
  os << "}";
  return os;
}
template <class T, size_t n>
ostream &operator<<(ostream &os, const array<T, n> &t) {
  os << "{";
  for (int i = 0; i < (n); i++) {
    os << t[i] << ",";
  }
  os << "}";
  return os;
}
template <class S, class T>
ostream &operator<<(ostream &os, const pair<S, T> &t) {
  return os << "(" << t.first << "," << t.second << ")";
}
const long long int INF = 1e9 + 7;
struct UnionFind {
  std::vector<int> data;
  std::vector<long long int> Value;
  UnionFind(int size, vector<long long int> val) : data(size, -1), Value(val) {}
  bool unite(int x, int y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x]) std::swap(x, y);
      data[x] += data[y];
      data[y] = x;
      Value[x] += Value[y];
    }
    return x != y;
  }
  bool find(int x, int y) { return root(x) == root(y); }
  int root(int x) { return (data[x] < 0) ? x : data[x] = root(data[x]); }
  int size(int x) { return -data[root(x)]; }
  long long int value(int x) { return Value[root(x)]; }
};
int main() {
  ios_base::sync_with_stdio(false);
  long long int N, M, ans = 0;
  long long int A[100005], B[100005], second[100005];
  vector<pair<long long int, pair<int, int>>> v;
  cin >> N >> M;
  vector<long long int> first(N);
  for (int i = 0; i < (N); i++) cin >> first[i];
  for (int i = 0; i < (M); i++) {
    cin >> A[i] >> B[i] >> second[i];
    A[i]--;
    B[i]--;
    v.emplace_back(second[i], pair<int, int>(A[i], B[i]));
  }
  sort((v).begin(), (v).end());
  UnionFind uf(N, first);
  pair<long long int, long long int> cut[100005] = {};
  vector<pair<int, UnionFind>> st;
  st.emplace_back(-1, uf);
  auto push_st = [&](int i, UnionFind &uf, int N) {
    int pcount = __builtin_popcount(N - i);
    while (st.size() && st.back().first >= i) st.pop_back();
    if (pcount == 1) st.emplace_back(i, uf);
  };
  vector<int> pre;
  priority_queue<pair<long long int, long long int>> que[100005];
  long long int req[100005];
  Fill(req, M);
  for (int i = 0; i < (M); i++) {
    pair<int, int> p = v[i].second;
    int r1 = uf.root(p.first);
    int r2 = uf.root(p.second);
    uf.unite(p.first, p.second);
    if (uf.value(p.first) < v[i].first) {
    }
    auto val = uf.value(p.first);
    if (r1 != uf.root(p.first)) swap(r1, r2);
    while (que[r1].size()) {
      pair<long long int, long long int> t = que[r1].top();
      if (t.first <= val) {
        req[t.second] = i;
        que[r1].pop();
      } else {
        break;
      }
    }
    while (que[r2].size()) {
      pair<long long int, long long int> t = que[r2].top();
      que[r2].pop();
      if (t.second <= val) {
        req[t.second] = i;
      } else {
        que[r1].push(t);
      }
    }
    if (val < v[i].first) {
      req[i] = -1;
      que[r1].emplace(v[i].first, i);
    }
  }
  bool safe[100005] = {};
  safe[M] = true;
  for (int i = (M)-1; i >= 0; i--) {
    if (req[i] == -1 || !safe[req[i]]) {
      ans++;
    } else {
      safe[i] = true;
    }
  }
  cout << ans << endl;
  return 0;
}
