// Slower C++ solution:
/*input

6 10

4 4 1 1 1 7

3 5 19

2 5 20

4 5 8

1 6 16

2 3 9

3 6 16

3 4 1

2 6 20

2 4 19

1 2 9

*/

#include <bits/stdc++.h>

#include <ext/pb_ds/assoc_container.hpp>

using namespace std;

using namespace __gnu_pbds;

#define REP(i, j, k)  for(int i = j; i <  k; ++i)

#define RREP(i, j, k) for(int i = j; i >= k; --i)

#define F first

#define S second

#define mp make_pair

#define pb emplace_back

#define PII pair<int , int>

#define DBGG(i,j)     cout << i << " " << j << endl

#define DB4(i,j,k,l)  cout << i << " " << j << " " << k << " " << l << endl

#define IOS cin.tie(0) , cout.sync_with_stdio(0)

#define endl "\n"

///------------------------------------------------------------

#define int long long

#define MAX 100009

#define INF 0x3f3f3f3f



struct djs{

    int x[MAX] , v[MAX] , siz[];

    void init(){ REP(i , 0 , MAX) x[i] = i; }

    int Find(int now){ return x[now] == now ? now : Find(x[now]); }

    void Union(int a , int b){

        a = Find(a) , b = Find(b);

        if(v[a] > v[b]) swap(a , b);

        x[a] = b;

        v[b] += v[a];

    }

    int operator[](int now){ return Find(now); }

} ds;



int n , m , e[MAX][3] , x[MAX] , in[MAX] , s[MAX];

int cut[MAX][2] , rrr[MAX][2] , is[MAX];

int cmp(int a , int b){ return e[a][2] < e[b][2]; }

int32_t main(){

    IOS;

    cin >> n >> m;

    REP(i , 1 , n + 1) cin >> x[i];

    REP(i , 1 , m + 1) REP(j , 0 , 3) cin >> e[i][j];

    REP(i , 1 , m + 1) s[i] = i;

    sort(s + 1 , s + 1 + m , cmp);

    

    ds.init();

    REP(i , 1 , n + 1) ds.v[i] = x[i];



    REP(idx , 1 , m + 1){ int i = s[idx];

        int v1 = e[i][0] , v2 = e[i][1];



        if(ds[v1] != ds[v2]){

            is[i] = 1;

            rrr[i][0] = ds[v1];

            cut[i][0] = ds.v[ds[v1]];

            rrr[i][1] = ds[v2];

            cut[i][1] = ds.v[ds[v2]];

            ds.Union(v1 , v2);

        }

                // cout << "\t\t\t"; REP(i , 1 , n + 1) cout << ds.x[i] << " "; cout << endl;

                // cout << "\t\t\t"; REP(i , 1 , n + 1) cout << ds.v[i] << " "; cout << endl;

    }

    int ans = 0;

    RREP(idx , m , 1){ int i = s[idx];

        int v1 = e[i][0] , v2 = e[i][1];

        // DB4("edge " , e[i][2] , "vs = " , ds.v[ds[v1]]);

        //         DB4(rrr[i][0] , cut[i][0] , rrr[i][1] , cut[i][1]);

        if(ds.v[ds[v1]] < e[i][2]){

            ans ++;

            if(is[i]){

                ds.x[rrr[i][0]] = rrr[i][0] , ds.v[rrr[i][0]] = cut[i][0];

                ds.x[rrr[i][1]] = rrr[i][1] , ds.v[rrr[i][1]] = cut[i][1];

                // cout << "\t\t\t"; REP(i , 1 , n + 1) cout << ds.x[i] << " "; cout << endl;

            }

        }

    }

    cout << ans << endl;

    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 1.788663761528196x):
/*input

10 9

81 16 73 7 2 61 86 38 90 28

6 8 725

3 10 12

1 4 558

4 9 615

5 6 942

8 9 918

2 7 720

4 7 292

7 10 414

*/

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef double lf;

typedef pair<ll,ll> ii;

#define REP(i,n) for(int i=0;i<n;i++)

#define REP1(i,n) for(ll i=1;i<=n;i++)

#define RST(i,n) memset(i,n,sizeof i)

#define SZ(a) (int)a.size()

#define ALL(a) a.begin(),a.end()

#define X first

#define Y second

#define mkp make_pair

#define pb push_back

#define eb emplace_back

#define pob pop_back

#ifdef cold66

#define debug(...) do{\

    fprintf(stderr,"%s - %d (%s) = ",__PRETTY_FUNCTION__,__LINE__,#__VA_ARGS__);\

    _do(__VA_ARGS__);\

}while(0)

template<typename T>void _do(T &&_x){cerr<<_x<<endl;}

template<typename T,typename ...S> void _do(T &&_x,S &&..._t){cerr<<_x<<", ";_do(_t...);}

template<typename _a,typename _b> ostream& operator << (ostream &_s,const pair<_a,_b> &_p){return _s<<"("<<_p.X<<","<<_p.Y<<")";}

template<typename It> ostream& _OUTC(ostream &_s,It _ita,It _itb)

{

    _s<<"{";

    for(It _it=_ita;_it!=_itb;_it++)

    {

        _s<<(_it==_ita?"":",")<<*_it;

    }

    _s<<"}";

    return _s;

}

template<typename _a> ostream &operator << (ostream &_s,vector<_a> &_c){return _OUTC(_s,ALL(_c));}

template<typename _a> ostream &operator << (ostream &_s,set<_a> &_c){return _OUTC(_s,ALL(_c));}

template<typename _a,typename _b> ostream &operator << (ostream &_s,map<_a,_b> &_c){return _OUTC(_s,ALL(_c));}

template<typename _t> void pary(_t _a,_t _b){_OUTC(cerr,_a,_b);cerr<<endl;}

#define IOS()

#else

#define debug(...)

#define pary(...)

#define endl '\n'

#define IOS() ios_base::sync_with_stdio(0);cin.tie(0);

#endif // cold66

//}

template<class T> inline bool chkmax(T &a, const T &b) { return b > a ? a = b, true : false; }

template<class T> inline bool chkmin(T &a, const T &b) { return b < a ? a = b, true : false; }

template<class T> using MaxHeap = priority_queue<T>;

template<class T> using MinHeap = priority_queue<T, vector<T>, greater<T>>;



const ll MAXn=1e5+5,MAXlg=__lg(MAXn)+2;

const ll MOD=1000000007;

const ll INF=0x3f3f3f3f;



struct edge{

  ll u,v,W;

  bool operator < (const edge &a) const {

    return W < a.W;

  }

};

vector<edge> e;

ll w[MAXn];

ll dsu[MAXn],szw[MAXn],sz[MAXn];

ll V[MAXn];

bitset<MAXn> ok;

ll fnd(ll x){

  if (x == dsu[x]) return x;

  return fnd(dsu[x]);

}

void mrg(ll x,ll y){

  dsu[y] = x;

  szw[x] += szw[y];

  sz[x] += sz[y];

}

long long tmp[100009][2];

long long ttt[100009][2];

int main(){

  IOS();

  ll n,m;

  cin >> n >> m;

  REP (i,n) {

    cin >> w[i];

    dsu[i] = i, szw[i] = w[i], sz[i] = 1;

  }

  REP (i,m) {

    ll u,v,W;

    cin >> u >> v >> W;

    u--,v--;

    e.eb((edge){u,v,W});

  }



  sort(ALL(e));

  REP (i,SZ(e)) {

    ll u = fnd(e[i].u), v = fnd(e[i].v);

    if (u == v) continue;

    debug(e[i].W);

    if (sz[u] < sz[v]) {

      swap(u,v);

      swap(e[i].u,e[i].v);

    }

    // V[e[i].v] = v;

    ok[i] = true;

    tmp[i][0] = u;

    tmp[i][1] = szw[u];

    ttt[i][0] = v;

    ttt[i][1] = szw[v];

    mrg(u,v);

  }



  ll ans = 0;

  for (ll i=SZ(e)-1;i>=0;i--) {

    // debug(szw[fnd(e[i].u)]);

    // debug(e[i].u,e[i].v,e[i].W);

    ll u = fnd(e[i].u);

    if (szw[u] >= e[i].W) continue;

    ans++;

    // debug(lr[i]);

    if (!ok[i]) continue;

    // debug(V[e[i].v]);

    // dsu[V[e[i].v]] = V[e[i].v];

    dsu[ttt[i][0]] = ttt[i][0];

    szw[ttt[i][0]] = ttt[i][1];

    dsu[tmp[i][0]] = tmp[i][0];

    szw[tmp[i][0]] = tmp[i][1];

    // szw[u] = tmp[i];

    // szw[u] -= szw[V[e[i].v]];

    // debug(szw[V[e[i].v]],szw[u]);

  }

  cout << ans << endl;

}