/*Bismillahir Rahmanir Rahim*///{
#include <bits/stdc++.h>
#include <ext/numeric>
using namespace std; using __gnu_cxx::power;
using ll = long long; using ull = unsigned long long; using ld = long double;
const ll llinf = (1ll<<61)-1; const double eps = 1e-6, ldeps = 1e-9;
struct Dbg { static constexpr auto &os = cout;   // replace by cerr in interactive.
template<class C> static auto dud(C *x)->decltype(os << *x, 0);
template<class C> static char dud(...);
template<class C> typename enable_if<sizeof dud<C>(0)!=1,Dbg&>::type operator<<(const C &x) {os<<x; return *this;}
template<class C> Dbg &dump(C b, C e) {
    for (struct{C i;int j;} i={(*this<<"\n[",b),0}; i.i!=e and i.j<26; i.i++, i.j++) *this<<", "+2*(i.i==b)<<*i.i;
    return *this << ']';
}
template<class C> typename enable_if<sizeof dud<C>(0)==1, Dbg&>::type operator<<(const C &x) {
    return dump(begin(x), end(x));
}
template<class C, size_t X> typename enable_if<!is_same<C, const char>::value, Dbg&>::type operator<<(C (&x)[X]) {
    return dump(begin(x), end(x));
}
template<class B, class C> Dbg &operator<<(const pair<B, C> &x) {return *this<<'{'<<x.first<<", "<<x.second<<'}';}
Dbg &operator<<(ostream&(*x)(std::ostream&)) { os << x; return *this; }
} dbg;
void err(istringstream *iss) { delete iss; }
template<class C, class... Args> void err(istringstream *iss, const C &val, const Args &... args) {
    string name; *iss >> name; if (name.back()==',') name.pop_back();
    dbg << name << " = " << val << "; ", err(iss, args...);
}
#define bug(args...) dbg << __LINE__ << ": ", err(new istringstream(#args), args), dbg << endl
#define cbug(a, args...) if (a) bug(args);
#define ASSERT(a, o, b, args...) if (!((a)o(b))) bug(a, b, ##args), assert((a)o(b));
#define sl(a) int(strlen(a))
#define sz(a) int(a.size())
int T, Q, cn;//}
const int inf = 1000000007, mxn = 100005;


class DSU//{
{
    vector<int> dsupar;
public:
    int cntDSU;
    vector<ll> sx;
    vector<vector<int> > pend;

    void reset(int nd) {
        for (int i = 0; i <= nd; i++) dsupar[i] = i;
        cntDSU = nd;
    }

    DSU(int N, int noOfSets = -1) {
        dsupar.resize(N+5), sx.resize(N+5), pend.resize(N+5, vector<int>());
        reset(N+4);
        cntDSU = noOfSets==-1 ? N : noOfSets;
    }

    int find(int x) {
        return dsupar[x]==x ? x : dsupar[x] = find(dsupar[x]);
    }

    void union_(int u, int v) {
        if ((u = find(u))==(v = find(v))) return;
        if (sz(pend[u]) < sz(pend[v])) swap(u, v);
        dsupar[v] = u, sx[u] += sx[v], sx[v] = 0;
        pend[u].insert(pend[u].end(), begin(pend[v]), end(pend[v])), pend[v].clear(), pend[v].shrink_to_fit();
        cntDSU--;
    }
};//}

DSU dsu(mxn);

int n, m, x[mxn];
pair<int, pair<int, int> > e[mxn];
bitset<mxn> good;

signed main() { cin.tie(0)->sync_with_stdio(0); cin.exceptions(cin.failbit); cout.precision(11), cout.setf(ios::fixed);
/*
It's clear that higher weighted edge of same component is worse than lower weighted one. After deleting edge component
increases and get new max edges, which is pretty tough to maintain. But we can do somthing similar in reverse (adding edge
in ascending instead of deleting in descending): we need to maintain not yet ok edges of each component whenever a component
becomes ok, we shall ok all its not yet ok edges. I have seen this reverse processing trick various times:
https://codeforces.com/contest/464/problem/C, https://codeforces.com/problemset/problem/1139/E
*/
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> x[i], dsu.sx[i] = x[i];
    }
    for (int i = 0; i < m; i++) {
        cin >> e[i].second.first >> e[i].second.second >> e[i].first;
    }
    sort(e, e+m);
    for (int i = 0; i < m; i++) {
        dsu.union_(e[i].second.first, e[i].second.second);
        int u = dsu.find(e[i].second.first);
        dsu.pend[u].push_back(i);
        if (dsu.sx[u]>=e[i].first) {
            for (auto &j : dsu.pend[u]) {
                good[j] = 1;
            }
            dsu.pend[u].clear();
        }
    }
    cout << m-good.count() << '\n';
}

Measured memory_bytes: 8048