#ifndef KOMAKI_LOCAL
#define NDEBUG
#endif

#include <bits/stdc++.h>
#include <sys/time.h>
#include <unistd.h>
using namespace std;
#define i64         int64_t
#define rep(i, n)   for(i64 i = 0; i < ((i64)(n)); ++i)
#define sz(v)       ((i64)((v).size()))
#define bit(n)      (((i64)1)<<((i64)(n)))
#define all(v)      (v).begin(), (v).end()

std::string dbgDelim(int &i){ return (i++ == 0 ? "" : ", "); }
#define dbgEmbrace(exp) { int i = 0; os << "{"; { exp; } os << "}"; return os; }
template <class T> std::ostream& operator<<(std::ostream &os, std::vector<T> v);
template <class T> std::ostream& operator<<(std::ostream &os, std::set<T> v);
template <class T> std::ostream& operator<<(std::ostream &os, std::queue<T> q);
template <class T> std::ostream& operator<<(std::ostream &os, std::priority_queue<T> q);
template <class T, class K> std::ostream& operator<<(std::ostream &os, std::pair<T, K> p);
template <class T, class K> std::ostream& operator<<(std::ostream &os, std::map<T, K> mp);
template <class T, class K> std::ostream& operator<<(std::ostream &os, std::unordered_map<T, K> mp);
template <int INDEX, class TUPLE> void dbgDeploy(std::ostream &os, TUPLE tuple){}
template <int INDEX, class TUPLE, class H, class ...Ts> void dbgDeploy(std::ostream &os, TUPLE t)
{ os << (INDEX == 0 ? "" : ", ") << get<INDEX>(t); dbgDeploy<INDEX + 1, TUPLE, Ts...>(os, t); }
template <class T, class K> void dbgDeploy(std::ostream &os, std::pair<T, K> p, std::string delim)
{ os << "(" << p.first << delim << p.second << ")"; }
template <class ...Ts> std::ostream& operator<<(std::ostream &os, std::tuple<Ts...> t)
{ os << "("; dbgDeploy<0, std::tuple<Ts...>, Ts...>(os, t); os << ")"; return os; }
template <class T, class K> std::ostream& operator<<(std::ostream &os, std::pair<T, K> p)
{ dbgDeploy(os, p, ", "); return os; }
template <class T> std::ostream& operator<<(std::ostream &os, std::vector<T> v)
{ dbgEmbrace( for(T t: v){ os << dbgDelim(i) << t; }); }
template <class T> std::ostream& operator<<(std::ostream &os, std::set<T> s)
{ dbgEmbrace( for(T t: s){ os << dbgDelim(i) << t; }); }
template <class T> std::ostream& operator<<(std::ostream &os, std::queue<T> q)
{ dbgEmbrace( for(; q.size(); q.pop()){ os << dbgDelim(i) << q.front(); }); }
template <class T> std::ostream& operator<<(std::ostream &os, std::priority_queue<T> q)
{ dbgEmbrace( for(; q.size(); q.pop()){ os << dbgDelim(i) << q.top();   }); }
template <class T, class K> std::ostream& operator<<(std::ostream &os, std::map<T, K> mp)
{ dbgEmbrace( for(auto p: mp){ os << dbgDelim(i); dbgDeploy(os, p, "->"); }); }
template <class T, class K> std::ostream& operator<<(std::ostream &os, std::unordered_map<T, K> mp)
{ dbgEmbrace( for(auto p: mp){ os << dbgDelim(i); dbgDeploy(os, p, "->"); }); }
#define DBG_OUT std::cerr
#define DBG_OVERLOAD(_1, _2, _3, _4, _5, _6, macro_name, ...) macro_name
#define DBG_LINE() { char s[99]; sprintf(s, "line:%3d | ", __LINE__); DBG_OUT << s; }
#define DBG_OUTPUT(v) { DBG_OUT << (#v) << "=" << (v); }
#define DBG1(v, ...) { DBG_OUTPUT(v); }
#define DBG2(v, ...) { DBG_OUTPUT(v); DBG_OUT << ", "; DBG1(__VA_ARGS__); }
#define DBG3(v, ...) { DBG_OUTPUT(v); DBG_OUT << ", "; DBG2(__VA_ARGS__); }
#define DBG4(v, ...) { DBG_OUTPUT(v); DBG_OUT << ", "; DBG3(__VA_ARGS__); }
#define DBG5(v, ...) { DBG_OUTPUT(v); DBG_OUT << ", "; DBG4(__VA_ARGS__); }
#define DBG6(v, ...) { DBG_OUTPUT(v); DBG_OUT << ", "; DBG5(__VA_ARGS__); }

#define DEBUG0() { DBG_LINE(); DBG_OUT << std::endl; }
#define DEBUG(...)                                                      \
  {                                                                     \
    DBG_LINE();                                                         \
    DBG_OVERLOAD(__VA_ARGS__, DBG6, DBG5, DBG4, DBG3, DBG2, DBG1)(__VA_ARGS__); \
    DBG_OUT << std::endl;                                               \
  }



class UnionFind
{
public:
    int getGroupId(int index);
    void putTogether(int index0, int index1);

    UnionFind();
    UnionFind(int size);

private:
    int size;
    std::vector<int> parents;
};

inline UnionFind::UnionFind()
{
}

inline UnionFind::UnionFind(int size)
{
  this->size = size;
  parents = std::vector<int>(size);
  for(int i = 0; i < size; ++i){
    parents[i] = i;
  }
}

inline void UnionFind::putTogether(int index0, int index1)
{
  parents[getGroupId(index0)] = getGroupId(index1);
}

inline int UnionFind::getGroupId(int index)
{
  if(parents[index] == index) return index;
  return parents[index] = getGroupId(parents[index]);
}




class Node
{
public:
    i64 child;
    i64 total_weight;
    bool ok;
    Node *child0;
    Node *child1;

    void print()
    {
      cout << "child: " << child << ", total weight: " << total_weight << endl;
      if(child0 != NULL) child0->print();
      if(child1 != NULL) child1->print();
    }

    void propagate(i64 heaviest, vector<i64> &weights)
    {
      heaviest = ok ? max(heaviest, total_weight) : heaviest;
      if (child != -1) {
        weights[child] = heaviest;
      } else {
        child0->propagate(heaviest, weights);
        child1->propagate(heaviest, weights);
      }
    }
};

Node build()
{

};





int main()
{
  i64 n, m;
  cin >> n >> m;
  vector<Node*> nodes;
  rep(i, n) {
    i64 weight;
    cin >> weight;
    Node* node = new Node;
    node->child = i;
    node->total_weight = weight;
    node->ok = true;
    node->child0 = NULL;
    node->child1 = NULL;
    nodes.push_back(node);
  }

  vector<pair<i64, pair<i64, i64>>> edges;
  rep(i, m) {
    i64 a, b, weight;
    cin >> a >> b >> weight;
    --a;
    --b;
    edges.push_back(make_pair(weight, make_pair(a, b)));
  }

  sort(all(edges));
  UnionFind uf(n);
  rep(i, m){
    i64 a = edges[i].second.first;
    i64 b = edges[i].second.second;
    a = uf.getGroupId(a);
    b = uf.getGroupId(b);
    if(a == b) continue;
    // DEBUG(a, b);
    Node* node = new Node;
    node->child = -1;
    node->total_weight = nodes[a]->total_weight + nodes[b]->total_weight;
    node->ok = edges[i].first <= node->total_weight;
    node->child0 = nodes[a];
    node->child1 = nodes[b];
    uf.putTogether(a, b);
    nodes[uf.getGroupId(a)] = node;
  }

  vector<i64> weights(n, -1);
  // nodes[uf.getGroupId(0)]->print();
  nodes[uf.getGroupId(0)]->propagate(-1, weights);

  i64 res = 0;
  rep(i, m){
    if(edges[i].first <= weights[edges[i].second.first]) res += 1;
  }
  cout << m - res << endl;
}














Measured memory_bytes: 16492