#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, set<pair<LL,LL>>& used_edge, set<pair<LL,LL>>& used_set){
    for(pair<LL,LL> p: edge[node]){
        LL next = p.first;
        pair<LL,LL> n(node, next);
        if(used_edge.count(n) > 0 || used_set.count(n) > 0) continue;
        used_edge.insert(n);
        dfs(next, edge, th, used_edge, used_set);
    }
}

int main(){
    LL n, m;
    cin >> n >> m;
    vector<LL> node_w(n);
    vector<vector<pair<LL,LL>>> edge(n);
    vector<Edge> edgel(n);
    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, y);
        edge[b].emplace_back(a, y);
        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<LL> acceptable(n);
    for(LL i = 0; i < m; ++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){
            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);
            total[na] = wa + wb;
            max_edge_w[na] = max<LL>(ea, eb);
            if(total[na] >= max_edge_w[na]){
                acceptable[na] = i+1;
            }
        }
    }

    vector<pair<LL,LL>> ao;
    for(LL i = 0; i < n; ++i){
        ao.emplace_back(-acceptable[i], i);
    }

    set<pair<LL,LL> used;
    set<pair<LL,LL>> erase_edge;
    LL cur = 0;
    for(LL i = m-1; i >= 0; --i){
        while(cur < ao.size() && -ao[cur].first > i){
            dfs(ao[cur].second, edge, i+1, used, erase_edge);
            ++cur;
        }
        erase_edge.insert(pair<LL,LL>(edgel[i].a, edgel[i].b));
    }

    cout << m - used.size() << endl;

    return 0;
}

