#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<random>
using namespace std;
random_device __RD; mt19937 Rand(__RD());
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Rep(i,j,k) for(int i=j;i>=k;i--)
#define int long long
#define lowbit(x) ((x)&(-x))
template<typename type>
inline void read(type &x){
x=0;bool flag(0);char ch=getchar();
while(!isdigit(ch)) flag^=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
flag?x=-x:0;
}
template<typename type>
inline void write(type x){
x<0?x=-x,putchar('-'):0;
static short Stack[50],top(0);
do Stack[++top]=x%10,x/=10;while(x);
while(top) putchar(Stack[top--]|48);
}
inline char read(char &ch){return ch=getchar();}
inline char write(const char &ch){return putchar(ch);}
template<typename type,typename ...T>
inline void read(type &x,T&...y){read(x),read(y...);}
template<typename type,typename ...T>
inline void write(type x,T...y){write(x),putchar(' '),write(y...),sizeof...(y)^1?0:putchar('\n');}
const int N=1e5+5,Mod=1e9+7;
int n,m,a,b,k,ans;
int rt[N],tot,ls[N<<2],rs[N<<2],t[N<<2];
void push_up(int c){
t[c]=max(t[ls[c]],t[rs[c]]);
}
void update(int &c,int l,int r,int x,int k){
if(l>r||k<0) return;
if(!c) c=++tot;
if(l==r){
t[c]=max(t[c],k);
return;
}
int mid=(l+r)>>1;
if(x<=mid) update(ls[c],l,mid,x,k);
else update(rs[c],mid+1,r,x,k);
push_up(c);return;
}
int query(int &c,int l,int r,int ql,int qr){
if(ql>qr||l>r||c==0) return 0;
if(ql<=l&&qr>=r) return t[c];
int mid=(l+r)>>1,res=0;
if(l<=mid) res=query(ls[c],l,mid,ql,qr);
if(r>mid) res=max(res,query(rs[c],mid+1,r,ql,qr));
return res;
}
signed main(){
read(n);read(m);
For(i,1,m){
read(a);read(b);read(k);
int Q=query(rt[a],0,N,0,k-1)+1;
update(rt[b],0,N,k,Q);
}
For(i,1,n) ans=max(ans,t[rt[i]]);
write(ans);
return 0;
}