#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <cassert>

using namespace std;
typedef long long LL;
template <typename F, typename S> std::ostream& operator<<(ostream& os, const pair<F,S>& p) {
    os << "(" << p.first << "," << p.second << ")"; return os; }
template <typename T> ostream& operator<<(ostream& os, const vector<T>& v) {
    os << "["; for(const T& a: v){ os << a << ", "; } os << "]"; return os; }
template <typename K, typename V> ostream& operator<<(ostream& os, const map<K,V>& m) {
    os << "{"; for(const auto& p: m){ os << p.first <<":"<< p.second << ", "; } os << "]"; return os; }


struct UnionFind{
    vector<LL> node_id;

    UnionFind(LL n):node_id(n){ for(LL i = 0; i < n; ++i) node_id[i] = i; }
    LL get(LL v){
        if(node_id[v] < 0) return node_id[v];
        if(v == node_id[v]){ return v;
        }else{ return node_id[v] = get(node_id[v]); }
    }
    void unite(LL u, LL v){
        LL u_id = get(u), v_id = get(v);
        node_id[u_id] = v_id;
    }
};


struct Edge{
    LL y, a, b, i;
    Edge(){}
    Edge(LL y_, LL a_, LL b_, LL i_){
        y = y_; a = a_; b = b_; i = i_;
    }
    bool operator<(const Edge& e) const{
        return this->y < e.y;
    }
};


void dfs(LL node, vector<vector<pair<LL,LL>>>& edge, LL th, vector<LL>& used_edge, vector<LL>& edge_ord){
    for(pair<LL,LL> p: edge[node]){
        LL next_node = p.first;
        LL edge_id = p.second;
        LL ord = edge_ord[edge_id];
        if(ord > th) continue;
        if(used_edge[edge_id]) continue;
        used_edge[edge_id] = 1;
        //cerr << "node=" << node << ", edge_id=" << edge_id << ", ord=" << edge_ord[edge_id] << ", th=" << th << endl;
        dfs(next_node, edge, th, used_edge, edge_ord);
    }
}

int main(){
    LL n, m;
    cin >> n >> m;
    vector<LL> node_w(n);
    vector<vector<pair<LL,LL>>> edge(n);
    vector<Edge> edgel;
    for(LL i = 0; i < n; ++i){
        cin >> node_w[i];
    }
    for(LL i = 0; i < m; ++i){
        LL a, b, y;
        cin >> a >> b >> y;
        --a; --b;
        edge[a].emplace_back(b, i);
        edge[b].emplace_back(a, i);
        edgel.emplace_back(y, a, b, i);
    }
    sort(edgel.begin(), edgel.end());
    UnionFind uf(n);
    vector<LL> total = node_w;
    vector<LL> max_edge_w(n);
    vector<pair<LL,LL>> acceptable;
    vector<LL> edge_ord(m);
    for(LL i = 0; i < m; ++i){
        edge_ord[edgel[i].i] = i;
        LL y = edgel[i].y;
        LL a = edgel[i].a;
        LL b = edgel[i].b;
        LL ai = uf.get(a);
        LL bi = uf.get(b);
        if(ai == bi){
            max_edge_w[ai] = max<LL>(y, max_edge_w[ai]);
            if(total[ai] >= max_edge_w[ai]){
                acceptable.emplace_back(ai, i);
            }
        }else{
            LL wa = total[ai];
            LL wb = total[bi];
            LL ea = max_edge_w[ai];
            LL eb = max_edge_w[bi];
            uf.unite(a, b);
            LL na = uf.get(a);
            assert(0 <= na && na < n);
            total[na] = wa + wb;
            max_edge_w[na] = max<LL>(y, max<LL>(ea, eb));
            if(total[na] >= max_edge_w[na]){
                acceptable.emplace_back(na, i);
            }
        }
    }

    vector<LL> used_node(n);
    vector<LL> used_edge(m);
    reverse(acceptable.begin(), acceptable.end());
    for(LL i = 0; i < acceptable.size(); ++i){
        LL node = acceptable[i].first;
        LL th = acceptable[i].second;
        if(used_node[node]) continue;
        dfs(node, edge, th, used_edge, edge_ord);
        used_node[node] = 1;
    }

    cout << m - accumulate(used_edge.begin(), used_edge.end(), 0) << endl;

    return 0;
}



Measured memory_bytes: 25324