#include <iostream>
#include <queue>
#include <set>
using namespace std;
 
struct nod
{
    int val, cost;
};
vector <nod> grf[100001];
queue <int> coada;
int d[100001];
bool ok;
int ccost[100001];
bool incoada[100001], visited[100001], viz2[100001];

int starters[100001], noduri[100001], nd, nrnd, st, nrfin;
bool okglob;

set<int> stfin, stf;
set<int>::iterator it;

void dfs(int k)
{
	int i, j;
	stfin.insert(k);
	viz2[k]=1;
	for(j=1; j<=nrnd; j++)
	{
		if(k==noduri[j])
		{
			for(it=stfin.begin(); it!=stfin.end(); it++)
			{
				stf.insert((*it));
			}
			stf.insert(k);
		}
	}
	for(i=0; i<grf[k].size(); i++)
	{
		if(viz2[grf[k][i].val])
			continue;
		dfs(grf[k][i].val);
		
	}
	
	stfin.erase(k);
}
	

int main()
{
    int n, m, i, a, b, c;
    cin>>n>>m;
    for(i=1; i<=m; i++)
    {
        cin>>a>>b>>c;
        nod act;
        act.val=b;
        act.cost=c;
        grf[a].push_back(act);
    }
    for(i=1; i<=n; i++)
    {
        d[i]=10000000;
    }
	for(nd=1; nd<=n; nd++)
	{
		if(visited[nd])
			continue;
		else
		{
			st++;
			starters[st]=nd;
		}
		coada.push(nd);
		d[nd]=0;
		incoada[nd]=1;
		while(!coada.empty() && !ok)
		{
			int cx=coada.front();
			visited[cx]=1;
			coada.pop();
			incoada[cx]=0;
			for(i=0; i<grf[cx].size(); i++)
			{
				if(d[cx]+grf[cx][i].cost<d[grf[cx][i].val])
				{
					d[grf[cx][i].val]=d[cx]+grf[cx][i].cost;
					if(!incoada[grf[cx][i].val])
					{
						if(ccost[grf[cx][i].val]>n)
						{
							nrnd++;
							ok=true;
							noduri[nrnd]=grf[cx][i].val;
							nrnd++;
							noduri[nrnd]=cx;
						}
						else
						{
							coada.push(grf[cx][i].val);
							ccost[grf[cx][i].val]++;
							incoada[grf[cx][i].val]=1;
						}
					}
				}
			}
		}
		while(!coada.empty())
		{
			coada.pop();
		}
		ok=false;
	}
	for(i=1; i<=st; i++)
	{
		dfs(starters[i]);
	}
	cout<<stf.size();
	
}