#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <stack>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <algorithm>

#define int long long
#define MOD7 1000000007
#define MOD9 1000000009

#define rep(i, n) for (int i = 0; i < (n); i++)
#define itrep(i, a) for (auto i = (a).begin(); i != (a).end(); i++)
#define REP(i, a, n) for (int i = (a); i <= (n); i++)
#define all(a) (a).begin(), (a).end()
#define mp(a, b) make_pair((a), (b))

using namespace std;

int dx[4] = { 1, 0, -1, 0 };
int dy[4] = { 0, -1, 0, 1 };

template<class T> void inputVector(vector<T>& v, int n) {
    v.resize(n);
    for (int i = 0; i < v.size(); i++) cin >> v[i];
}

vector<int> X;

class UnionFind {
private:
    vector<int> sums;
    vector<int> roots;
    vector<multiset<int>> hangEdges;
    vector<vector<int>> children;

public:
    UnionFind(int size) {
        rep(i, size) {
            roots.push_back(i);
            children.push_back(vector<int>(1, i));
            sums.push_back(X[i]);
            hangEdges.push_back(multiset<int>());
        }
    }

    int root(int x) {
        return roots[x];
    }

    void unite(int x, int y) {
        int rootX = roots[x];
        int rootY = roots[y];
        if (rootX == rootY) return;
        if (children[rootX].size() < children[rootY].size()) {
            for (int child : children[rootX]) {
                roots[child] = roots[rootY];
            }
            children[rootY].insert(children[rootY].end(), all(children[rootX]));
            children[rootX].clear();
            hangEdges[rootY].insert(all(hangEdges[rootX]));
            hangEdges[rootX].clear();
            sums[rootY] += sums[rootX];
        } else {
            for (int child : children[rootY]) {
                roots[child] = roots[rootX];
            }
            children[rootX].insert(children[rootX].end(), all(children[rootY]));
            children[rootY].clear();
            hangEdges[rootX].insert(all(hangEdges[rootY]));
            hangEdges[rootY].clear();
            sums[rootX] += sums[rootY];
        }
    }

    bool same(int x, int y) {
        return roots[x] == roots[y];
    }

    int count(int x) {
        return sums[roots[x]];
    }

    void hang(int x, int weight) {
        hangEdges[roots[x]].insert(weight);
    }

    int open(int x) {
        int rootX = roots[x];
        int cnt = count(rootX);

        int ret = 0;
        auto it = hangEdges[rootX].begin();
        while (it != hangEdges[rootX].end()) {
            int w = *it;
            if (w > cnt) break;
            ret++;
            it++;
        }
        hangEdges[rootX].erase(hangEdges[rootX].begin(), it);

        return ret;
    }
};

struct Edge {
    int a, b, w;
    Edge(int a, int b, int w) : a(a), b(b), w(w) {
    }

    bool operator< (const Edge &a) const {
        return w < a.w;
    }
};


signed main() {
    int N, M;
    cin >> N >> M;

    inputVector(X, N);

    vector<Edge> edges;
    rep(i, M) {
        int a, b, w;
        cin >> a >> b >> w;
        a--; b--;
        edges.push_back(Edge(a, b, w));
    }
    sort(all(edges));

    UnionFind uf(N);

    int ret = M;
    for (auto &e : edges) {
        //cerr << "edge(" << e.a << ", " << e.b << ", " << e.w << ")" << endl;
        uf.unite(e.a, e.b);
        uf.hang(e.a, e.w);
        //cerr << "count:" << uf.count(e.a) << endl;
        if (e.w <= uf.count(e.a)) {
            ret -= uf.open(e.a);
        }
    }

    cout << ret << endl;

    return 0;
}


Measured memory_bytes: 27244