//{{{ #include <bits/stdc++.h>
#ifndef __clang__
#include <bits/stdc++.h>
#endif
using namespace std; //}}}
const long long MOD = static_cast<int>(1e9) + 7;
//{{{TEMPLATE_BEGIN
#include <unistd.h>
using namespace std::rel_ops;
typedef long long lint;
typedef unsigned long long ulint;
typedef long double ldouble;
typedef vector<int> vint;
#define rep(i, n)                                                              \
    for (int i = 0, i##_len = static_cast<int>(n); i < i##_len; i++)
#define all(c) begin(c), end(c)
#define perm(c)                                                                \
    sort(all(c));                                                              \
for (bool c##p = 1; c##p; c##p = next_permutation(all(c)))
#define uniquenize(v) (v).erase(unique(all(v)), end(v))
#define cauto const auto &
#define memset(x, y) memset(x, y, sizeof(x))
#define popcount __builtin_popcount
#define gcd __gcd
inline lint bit(int x) {
    return 1LL << x;
}
template <class T>
inline int size(const T &a) {
    return (int)a.size();
}
template <class T>
inline bool chmin(T &a, const T &b) {
    return a > b ? a = b, 1 : 0;
}
template <class T>
inline int clamp(T v, T lo, T hi) {
    return (v > hi) - (v < lo);
}
template <class T>
inline bool chmax(T &a, const T &b) {
    return a < b ? a = b, 1 : 0;
}
template <class T>
inline pair<vector<T>, char> operator*(const vector<T> &v, const char &c) {
    return make_pair(v, c);
}
template <class T>
inline istream &operator>>(istream &is, vector<T> &v) {
#ifdef ZEROKUGI
    if (v.empty()) {
        cerr << "Error L" << __LINE__ << ": vector size is zero." << endl;
        exit(EXIT_FAILURE);
    }
#endif
    for (auto &x : v)
        is >> x;
    return is;
}
template <class T>
inline ostream &operator<<(ostream &os, const pair<vector<T>, char> &v) {
    bool t = 0;
    for (const T &x : v.first) {
        if (t)
            os << v.second;
        os << x;
        t = 1;
    }
    return os;
}
template <class T>
inline ostream &operator<<(ostream &os, vector<T> &v) {
    return os << v * ' ';
}
struct before_main {
    before_main() {
        cin.tie(0);
        ios::sync_with_stdio(0);
        cout << fixed << setprecision(20);
    };
} __before_main;
//}}}TEMPLATE_END

lint vw[100010];
lint edge_no[100010];

vector<int> pending[100010];

class UnionFind {
    vector<int> par;

    public:
    int root(int a) {
        if(a == par[a]) return a;
        return par[a] = root(par[a]);
    }

    UnionFind(int size) : par(size) {iota(begin(par), end(par), 0);}
    void unite(int A, int B) {
        int rb = root(B);
        int ra = root(A);
        if(rb != ra) {
            lint tmp = vw[rb] + vw[ra];
            vw[rb] = vw[ra] = tmp;
            tmp = edge_no[ra] + edge_no[rb];
            edge_no[ra] = edge_no[rb] = tmp;
        }
        par[root(B)] = root(A);
    }
    bool eq(int A, int B) { return root(B) == root(A);}
};

struct edge {
    int v, w, cost;
};

int main() {
    int n, m;
    cin >> n >> m;

    rep(i, n) {
        cin >> vw[i];
    }
    vector<edge> es;
    rep(i, m) {
        int a, b, y;
        cin >> a >> b >> y;
        a--;
        b--;
        es.push_back({a, b, y});
    }
    sort(all(es), [](const edge &p, const edge &q){
            return p.cost < q.cost;
            });

    UnionFind uf(n+5);
    for(const edge &e: es) {
        int pv = uf.root(e.v);
        if(uf.eq(e.v, e.w)) {
            if(vw[pv] >= e.cost) {
                // edge_no[pv] = 0;
                continue;
            } else {
                edge_no[pv]++;
            }
        } else {
            uf.unite(e.v, e.w);
            if(vw[pv] >= e.cost) {
                edge_no[pv] = 0;
            } else {
                edge_no[pv]++;
            }
        }
    }

    int ans = 0;
    vector<int> seen(n+5);
    rep(i, n) {
        int j = uf.root(i);
        if(seen[j]) continue;
        seen[j] = 1;
        ans += edge_no[j];
    }
    cout << ans << endl;
}


Measured memory_bytes: 6388