#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
	int x=0,f=1;char c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
#define N 400010
#define ll long long
int n,m,a[N],fa[N],id[N],cnt,ans;
bool isdel[N],flag[N];
ll value[N<<2];
struct data
{
	int x,y,z;
	bool operator <(const data&a) const
	{
		return z<a.z;
	}
}e[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
namespace kruskal_tree
{
	int p[N<<2],t,degree[N<<2],fa[N<<2];
	ll size[N<<2];
	struct data{int to,nxt;}edge[N<<2];
	void addedge(int x,int y){t++;degree[y]++;fa[y]=x;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
	void link(int x,int y,int i)
	{
		id[i]=++cnt;addedge(cnt,x),addedge(cnt,y);
	}
	void dfs(int k)
	{
		size[k]=a[k];
		for (int i=p[k];i;i=edge[i].nxt)
		{
			dfs(edge[i].to);
			size[k]+=size[edge[i].to];
		}
	}
	void build()
	{
		for (int i=1;i<=cnt;i++)
		if (!degree[i]) dfs(i);
	}
	void del()
	{	
		isdel[0]=1;
		for (int i=m;i>=1;i--)
		if (flag[i]&&isdel[fa[id[i]]]&&e[i].z>size[id[i]]) isdel[id[i]]=1;
	}
}
void dfs(int k)
{
	for (int i=kruskal_tree::p[k];i;i=kruskal_tree::edge[i].nxt)
	{
		dfs(kruskal_tree::edge[i].to);
		if (!isdel[k]) fa[find(kruskal_tree::edge[i].to)]=k;
	}
}
int main()
{
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read();
	sort(e+1,e+m+1);
	for (int i=1;i<=4*n;i++) fa[i]=i;cnt=n;
	for (int i=1;i<=m;i++)
	{
		int p=find(e[i].x),q=find(e[i].y);
		if (p!=q) kruskal_tree::link(p,q,i),fa[p]=fa[q]=id[i],flag[i]=1;
	}
	kruskal_tree::build();
	kruskal_tree::del();
	for (int i=1;i<=cnt;i++) fa[i]=i;
	for (int i=1;i<=cnt;i++)
	if (!kruskal_tree::degree[i]) dfs(i);
	for (int i=1;i<=m;i++)
	if (find(e[i].x)==find(e[i].y)&&kruskal_tree::size[find(e[i].x)]>=e[i].z) ans++;
	cout<<m-ans;
	return 0;
}