#include <bits/stdc++.h>
using namespace std;
struct edge {
    int a, b, y;
    bool operator<(const struct edge& rhs) const { return y < rhs.y; }
};
struct union_find {
    vector<long long> data;
    union_find(vector<int>& X) : data(X.size()) {
        for (int i = 0; i < X.size(); i++) data[i] = -X[i];
    }
    void unite(int x, int y) {
        if (root(x) == root(y)) return;
        if (size(x) < size(y)) swap(x, y);
        data[root(x)] += data[root(y)];
        data[root(y)] = root(x);
    }
    int root(int x) {
        if (data[x] < 0) return x;
        return data[x] = root(data[x]);
    }
    long long size(int x) {
        return -data[root(x)];
    }
};
int main()
{
    int N, M; cin >> N >> M;
    vector<int> X(N); for (int& x : X) cin >> x;
    vector<vector<pair<int, int>>> G(N);
    vector<edge> E(M); 
    for (auto& e : E) {
        cin >> e.a >> e.b >> e.y, e.a--, e.b--;
        G[e.a].emplace_back(e.b, e.y);
        G[e.b].emplace_back(e.a, e.y);
    }
    sort(begin(E), end(E));
    union_find uf(X);
    vector<int> candidate(M);
    for (int i = 0; i < E.size(); i++) {
        uf.unite(E[i].a, E[i].b);
        if (uf.size(E[i].a) >= E[i].y) {
            candidate[i] = 1;
        }
    }
    vector<int> visited(N);
    int cnt = 0;
    function<void(int, int)> recur;
    recur = [&](int x, int cost) {
        if (visited[x]) return;
        visited[x] = 1;
        for (auto p : G[x]) {
            if (p.second <= cost) {
                cnt++;
                recur(p.first, cost);
            }
        }
    };
    for (int i = E.size() - 1; i >= 0; i--) {
        if (candidate[i]) {
            recur(E[i].a, E[i].y);
        }
    }
    cout << M - cnt/2 << endl;
    return 0;
}