#include<iostream>
using namespace std;
int main(){
    int n,d,sum=0;
    cin >> n >> d;
    int a[n];
    for(int i=0;i<n;i++){
        cin >> a[i];
    }
    for(int i=2;i<n;i++){
        for(int j=1;j<i;j++){
            if(a[i]-a[j]<=d&&a[i]-a[j]>=-d)sum+=2;
        }
    }
    cout << sum;
    return 0;
}


#include <iostream>
#include <cmath>
using namespace std;
int main(){
	int a[1001],n,d,sum=0;
	cin>>n>>d;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
			if(abs(a[i]-a[j])<=d) sum++;
	cout<<sum*2<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int n,d,ans,a[2000];
int main()
{
	cin>>n>>d;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=2;i<=n;i++)
	  for(int j=1;j<i;j++)
	  {
	  	if(abs(a[i]-a[j])<=d) ans+=2;
	  }
	cout<<ans<<"\n";
	return 0;
 }


#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a[1010],d,n,i,ans=0,j;
	cin>>n>>d;
	for(i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+1+n);
	for(i=1;i<=n;i++)
	    for(j=1;j<i;j++)
	        if(a[i]-a[j]<=d&&a[i]-a[j]>=-d)
	            ans+=2;
	cout<<ans;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
int n,d,ans=0;
int a[1000+10];
int main(){
	cin>>n>>d;
	for (int i=1;i<=n;i++) cin>>a[i];

	for (int i=2;i<=n;i++)
    for (int j=1;j<i;j++){
        if(a[i]-a[j]<=d && a[i]-a[j]>=-d) ans+=2;
	}

	cout<<ans;
	return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
int a[1001],n,d,ans;
int main(){
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=2;i<=n;i++)for(int j=1;j<i;j++)if(a[i]-a[j]<=d&&a[i]-a[j]>=-d) ans+=2;
    printf("%d\n",ans);
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
int a[1001],n,ans;
int main()
{
	int k;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			if(abs(a[i]-a[j])<=k)
			{
				ans+=2;
			}
		}
	}
	cout<<ans<<endl;
	return 0;
 }


//#include<bits/stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<stack>
#include<vector>
//#include<conio.h>
#include<string>
#include<map>
#include<cstdlib>
#include<queue>
#include<math.h>
#include<time.h>
#include<set>
#include<cstdio>
#include<stdio.h>
#include<algorithm>
using namespace std;
using std::cin;
using std::cout;
using std::endl;
namespace IN{
    const int MAX_INPUT = 1000000;
    #define getc() (p1==p2&&(p2=(p1=buf)+inbuf->sgetn(buf,MAX_INPUT),p1==p2)?EOF:*p1++)
    char buf[MAX_INPUT],*p1,*p2;
    template<typename T>inline bool read(T &x) {
        static std::streambuf *inbuf=cin.rdbuf();
        x=0;
        register int f=0,flag=false;
        register char ch=getc();
        while(!isdigit(ch)){
            if (ch=='-') f=1;
        	ch=getc();
        }
        if(isdigit(ch)) x=x*10+ch-'0',ch=getc(),flag=true;
        while(isdigit(ch)) {
            x=x*10+ch-48;
            ch=getc();
        }
        x=f?-x:x;
        return flag;
    }
    template<typename T,typename ...Args>inline bool read(T& a,Args& ...args) {
       return read(a)&&read(args...);
    }
    #undef getc
}

namespace OUT{
    template<typename T>inline void put(T x){
        static std::streambuf *outbuf=cout.rdbuf();
        static char stack[21];
        static int top=0;
        if(x<0){
            outbuf->sputc('-');
            x=-x;
        }
        if(!x){
            outbuf->sputc('0');
            outbuf->sputc('\n');
            return;
        }
        while(x){
            stack[++top]=x%10+'0';
            x/=10;
        }
        while(top){
            outbuf->sputc(stack[top]);
            --top;
        }
        outbuf->sputc('\n');
    }
    inline void putc(const char ch){
        static std::streambuf *outbuf=cout.rdbuf();
        outbuf->sputc(ch);
    }
    inline void putstr(string s){
    	for(register int i=0;i<s.length();i++) putc(s[i]);
	}
    template<typename T>inline void put(const char ch,T x){
        static std::streambuf *outbuf=cout.rdbuf();
        static char stack[21];
        static int top = 0;
        if(x<0){
            outbuf->sputc('-');
            x=-x;
        }
        if(!x){
            outbuf->sputc('0');
            outbuf->sputc(ch);
            return;
        }
        while(x){
            stack[++top]=x%10+'0';
            x/=10;
        }
        while(top){
            outbuf->sputc(stack[top]);
            --top;
        }
        outbuf->sputc(ch);
    }
    template<typename T,typename ...Args> inline void put(T a,Args ...args){
        put(a);put(args...);
    }
    template<typename T,typename ...Args> inline void put(const char ch,T a,Args ...args){
        put(ch,a);put(ch,args...);
    }
}
using IN::read;
using OUT::put;
using OUT::putc;
using OUT::putstr;
int n,m,p[1005],ans;
int main(int argc, char const *argv[]){
    std::ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    read(n,m);
    for(int i=1;i<=n;i++) read(p[i]);
    for(int i=1;i<=n;i++)
    	for(int j=1;j<i;j++)
    		if(abs(p[i]-p[j])<=m) ans+=2;
    put(ans);
    return 0;
}


#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<cstdlib>
using namespace std;
int n,a[1001],m,ans;
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(i!=j&&a[j]-a[i]<=m) ans+=2;
	cout<<ans;
 	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int main(){
	long long n,d,a[1005],ans=0;
	cin>>n>>d;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+n+1);
	for(int i=1;i<n;i++)
		for(int j=i+1;j<=n;j++)
			if(a[j]-a[i]<=d)ans+=2;
				else break;
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long n,d,a[1001],b=0,i,j;
	cin>>n>>d;
	for(i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(i=1;i<=n;i++)
	{
		for(j=i+1;j<=n;j++)
		{
			if(a[i]-a[j]<=d&&a[i]-a[j]>=-d)
				b++;
		}
	}
	cout<<b*2;
	return 0;
}


#include<stdio.h>
#include<math.h>
int n,d,s[1001],cnt;
int main()
{
	scanf("%d%d",&n,&d);
	for(int i=0;i<n;i++)
		scanf("%d",&s[i]);
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)if(abs(s[i]-s[j])<=d&&i!=j)cnt++;
	printf("%d",cnt);
}


#include<iostream>
#include<cmath>
using namespace std;
int main(){
	int n,m,a[1000],i,j,k=0;
	cin>>n>>m;
	for(i=0;i<n;i++){
		cin>>a[i];
	}
	for(i=0;i<n;i++){
		for(j=i+1;j<n;j++){
			if(abs(a[i]-a[j])<=m)
				k++;
		}
	}
	cout<<k*2;
	return 0;
}


#include<iostream>
#include<cmath>
using namespace std;
int a[1005];
int main()
{
    int n,d,ans=0;
    cin>>n>>d;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
            if(abs(a[i]-a[j])<=d)
                ans+=2;
    cout<<ans;
    return 0;
}


#include<cstdio>
using namespace std;
int a[1005];
int main()
{
	int n,d,ans;
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]-a[j]<=d&&a[i]-a[j]>=-d)
				ans+=2;
    printf("%d\n",ans);
    return 0;
}


#include<iostream>
#include<cstdio>
using namespace std;
int a[1001],n,d,ans;
int main(){
    scanf("%d%d",&n,&d);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]-a[j]<=d&&a[i]-a[j]>=-d) ++ans;
    printf("%d\n",ans*2);
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
int n, a[1005], ans, d;
int main() {
    cin >> n >> d;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j < i; j++) {
            if(abs(a[i] - a[j]) <= d) ans += 2;
        }
    }
    cout << ans <<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
inline int read(){
	char c=getchar();int x=0;
	while(c<'0'||c>'9')c=getchar();
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}
int n,d,a[1005],ans;
int main(){
	n=read(),d=read();
	for(int i=1;i<=n;i++)
	    a[i]=read();
	for(int i=1;i<=n;i++)
	    for(int j=1;j<i;j++)
	        if(abs(a[i]-a[j])<=d)
	            ans+=2;
	printf("%d",ans);
	return 0;
}


// luogu-judger-enable-o2
#include<iostream>
using namespace std;
int n,d,a[1001],ans=0;
int main(){
	cin>>n>>d;
	for(int i=1;i<=n;i++)
		cin>>a[i];
	for(int i=2;i<=n;i++){
		for(int j=1;j<i;j++){
			if(i==j)
				continue;
			if(a[i]-a[j]<=d&&a[i]-a[j]>=-d)
				ans+=2;
		}
	}
	cout<<ans<<endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
int a[10005],sum;
int main(){
	int n,d;
	cin>>n>>d;
	for(int i=1;i<=n;i++)	cin>>a[i];
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(abs(a[i]-a[j])<=d)	sum++;
		}
	}
	cout<<sum<<endl;
	return 0;
}


#include<iostream>
#include<cmath>
using namespace std;
int n,sum,a[101],m;
int main()
{
	cin>>n>>m;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
		for(int j=i-1; j>=1; j--)
		{
			if(abs(a[i]-a[j])<=m) sum++;
		}
	}
	cout<<sum*2;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
vector<long long> p;
int main(){
	long long n,d,ans=0;
	cin>>n>>d;
	for(long long i=0;i<n;i++){
		long long a;
		cin>>a;
		p.push_back(a);
	}
	sort(p.begin(),p.end());
	for(long long i=0;i<n;i++){
		for(long long j=0;j<n;j++){
			if(i!=j){
				if(abs(p[j]-p[i])<=d)
					ans++;
			}
		}
	}
	cout<<ans;
	return 0;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int n,d;
	cin >> n >> d;
	int a[1005];
	for(int i=0; i<n; i++)
	{
		cin>>a[i];
	}
	sort(a, a+n);
	int ans = 0;
	for(int i=0;i<n;i++)
	{
		int cnt = 1;
		int j = i+1;
		while(j < n && a[j] - a[i] <= d) j++, cnt++;
		ans += cnt * (cnt - 1);
	}
	cout << ans;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int n,d;
	cin >> n >> d;
	int a[1005];
	for(int i=0; i<n; i++)
	{
		cin>>a[i];
	}
	sort(a, a+n);
	long long ans = 0;
	for(int i=0;i<n;i++)
	{
		int cnt = upper_bound(a + i, a + n, a[i] + d) - a - i;
		ans += cnt * (cnt - 1);
	}
	cout << ans;
}


#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int n,d;
	cin >> n >> d;
	int a[1005];
	for(int i=0; i<n; i++)
	{
		cin>>a[i];
	}
	sort(a, a+n);
	long long ans = 0;
	for(int i=0;i<n;i++)
	{
		int cnt = upper_bound(a + i, a + n, a[i] + d) - a - i;
		ans += (cnt -1) << 1;
	}
	cout << ans;
}


#include<bits/stdc++.h>
using namespace std;
const int N=1e3+3;
int a[N];
int main(){
    int n,d;
    cin>>n>>d;
    for(int i=0;i<n;i++)
    cin>>a[i];
    int cnt=0;
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++)
    cnt+=(abs(a[i]-a[j])<=d);
    cout<<cnt*2;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
const itn N=1e3+3;
int a[N];
int main(){
    int n,d;
    cin>>n>>d;
    for(int i=0;i<n;i++)
    cin>>a[i];
    int cnt=0;
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++)
    cnt+=(abs(a[i]-a[j])<=d);
    cout<<cnt*2;
    return 0;
}


// Copyright: FrenkieDeJong21
#include <bits/stdc++.h>
using namespace std;
#define PII pair<int, int>
#define LL long long

inline int read(){
	char c = getchar(); int f = 1, x = 0; while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar(); return x * f;
} const int _ = 1010;
int N, D, a[_], ans;

int main(){
	N = read(); D = read();
	for(int i = 1; i <= N; i++) a[i] = read();
	for(int i = 1; i <= N; i++)
		for(int j = 1; j <= N; j++) if(i != j && abs(a[i] - a[j]) <= D) ++ans;
	printf("%d\n", ans);
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int n,d,a[1010],ans,s[1010];
bool p[1010];
void dfs(int t)
{
	if(t>2)
	{
	    ans++;
		return;
	}
	for(int i=1; i<=n; i++)
	{
		s[0]=a[i];
		if(abs(a[i]-s[t-1])<=d&&!p[i])
		{
			p[i]=1;
			s[t]=a[i];
			dfs(t+1);
			p[i]=0;
		}
	}
}
int main()
{
	scanf("%d%d",&n,&d);
	for(int i=1; i<=n; i++)
	{
		scanf("%d",&a[i]);
	}
	dfs(1);
	printf("%d",ans);
	return 0;
}


#include<iostream>
using namespace std;
int main(){

	int n,d,a[1001];
	cout << "OK" << endl;
	cin >> n >> d;
	for(int i=0;i<n;i++){
		cin >> a[i];
	}

}


#include<iostream>
#include<algorithm>
using namespace std;
int main(){

	int n,d,a[1001];
	int c=0;
	cin >> n >> d;
	for(int i=0;i<n;i++)
		cin >> a[i];
	for(int i=1;i<n;i++){
		for(int j=0;j<i;j++){
			if(abs(a[i]-a[j])<=d){
				c++;
			}
		}

	}
	cout << c*2;
}


#include<bits/stdc++.h>
using namespace std;
int n,d;
int a[2000];
int main()
{
	scanf("%d%d",&n,&d);
	for(int i=1; i<=n; i++)
	 scanf("%d",a+i);
	int ans = 0;
	for(int i=1; i<=n; i++)
	 for(int j=1; j<=n; j++)
	  if( abs(a[i]-a[j])<=d && i!=j)
	    ans++;
	cout<<ans<<endl;
	return 0;
}


#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,d,i,j,ans;
int q[1005];
int main(){
	cin>>n>>d;
	for(i=1;i<=n;i++)
		cin>>q[i];
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			if(i!=j&&abs(q[i]-q[j])<=d)ans++;
	cout<<ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
int n,d,a[1001],ans=0;
int main()
{
	scanf("%d%d",&n,&d);
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=2;i<=n;i++){
		for(int j=1;j<i;j++)
			if(a[i]-a[j]<=d&&a[i]-a[j]>=-d)ans+=2;
	}
	printf("%d\n",ans);
	return 0;
}


#include <bits/stdc++.h>

#define loop(i,n)    for( int i=0; i<n; i++ )
#define loop1(i,a,n) for( int i=a; i<n; i++ )
#define vloop(i,a)   for( vector<ll>::iterator i=a.begin(); i!=a.end(); i++ )
#define dloop(i,a)   for( deque<char>::iterator i=a.begin(); i!=a.end(); i++ )
#define PI 3.14159265
#define bc __builtin_popcountll
#define gc getchar_unlocked
#define pc putchar_unlocked
#define pb push_back
#define pf push_front
#define rf pop_front
#define rb pop_back
#define mp make_pair
#define fs first
#define sc second
#define fi ios_base::sync_with_stdio(false); cin.tie(NULL)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll M = 1e9 + 7;
const ll INF = 1e9;

inline ll pwr(ll base,ll n,ll m){ll ans=1;while(n>0){if(n%2==1)ans=(ans*base)%m;base=(base*base)%m;n/=2;}return ans;}

const int sz = (int)1e5 + 2;
int n, m, w, a, b;
vector< map<int,int> > rec;

int Less_Than( int wt, int v ) {

    map<int,int>::iterator it = rec[v].lower_bound(wt);

    if( it == rec[v].begin() ) return 0;
    it--;
    return ((*it).sc);

}

int main() {
    fi;

    cin>>n>>m;
    int ans = 0;
    rec.resize(n+1);
    while(m--) {

        cin>>a>>b>>w;

        int endingAtA = Less_Than( w, a );
        int endingAtB = Less_Than( w+1, b );

        if( endingAtB > endingAtA + 1 )
            continue;

        ans = max(ans,endingAtA + 1 );

        rec[b][w] = max(rec[b][w], endingAtA + 1);
        // Remove records where
        // count of ( endingAtB with weight > w )
        // is less than count of ( endingAtB with weight = w )
        map<int,int>::iterator it = rec[b].upper_bound(w);

        do {
            if( it != rec[b].end() && (*it).sc < endingAtA + 1 ) {
                rec[b].erase(it);
                it = rec[b].upper_bound(w);
            }
        } while( it != rec[b].end() && (*it).sc < endingAtA + 1 );

    }

    cout<<ans;

    return 0;
}


#include <bits/stdc++.h>

#define loop(i,n)    for( int i=0; i<n; i++ )
#define loop1(i,a,n) for( int i=a; i<n; i++ )
#define vloop(i,a)   for( vector<ll>::iterator i=a.begin(); i!=a.end(); i++ )
#define dloop(i,a)   for( deque<char>::iterator i=a.begin(); i!=a.end(); i++ )
#define PI 3.14159265
#define bc __builtin_popcountll
#define gc getchar_unlocked
#define pc putchar_unlocked
#define pb push_back
#define pf push_front
#define rf pop_front
#define rb pop_back
#define mp make_pair
#define fs first
#define sc second
#define fi ios_base::sync_with_stdio(false); cin.tie(NULL)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll M = 1e9 + 7;
const ll INF = 1e9;

inline ll pwr(ll base,ll n,ll m){ll ans=1;while(n>0){if(n%2==1)ans=(ans*base)%m;base=(base*base)%m;n/=2;}return ans;}

const int sz = (int)1e5 + 2;
vector< pair< int, pair<int, int> > > adj[sz];
int n, m, w, a, b;
int dp[sz], dp1[sz];
bool vis[sz], vis1[sz];

int dfs( int curr, int rnk, int Wpre, int cnt ) {

    if( dp[rnk] != -1 )
        return max( cnt + dp[rnk], dp1[curr] );

    vis[curr] = true;
    int ans = cnt;
    int v1 = 0;

    for( vector< pair< int, pair<int, int> > >::iterator it = adj[curr].begin(); it != adj[curr].end(); it++ ) {

        int r = (*it).sc.sc;
        int w = (*it).sc.fs;
        int v = (*it).fs;

        if( r > rnk && w > Wpre )
            ans = max( ans, dfs( v, r, w, cnt + 1 ) );

        if( !vis1[v] ) {
            vis1[v] = true;
            v1 = max( v1, dfs( v, r, w, 1 ) );
        }

    }

    if( rnk != 0 )
        dp[rnk] = ans - cnt;
    dp1[curr] = v1;

    return max(ans,v1);

}

int main() {
    fi;

    cin>>n>>m;
    memset(dp,-1,sizeof(dp));
    memset(dp1,-1,sizeof(dp1));
    memset(vis,false,sizeof(vis));
    memset(vis1,false,sizeof(vis1));

    loop(i,m) {
        cin>>a>>b>>w;
        adj[a].pb(mp(b,mp(w,i+1)));
    }

    int ans = 0;
    loop(i,n) {
        if( !vis[i+1] )
            ans = max(ans, dfs(i+1,0,-1,0) );
    }
    cout<<ans;
    return 0;
}


#include <bits/stdc++.h>

#define loop(i,n)    for( int i=0; i<n; i++ )
#define loop1(i,a,n) for( int i=a; i<n; i++ )
#define vloop(i,a)   for( vector<ll>::iterator i=a.begin(); i!=a.end(); i++ )
#define dloop(i,a)   for( deque<char>::iterator i=a.begin(); i!=a.end(); i++ )
#define PI 3.14159265
#define bc __builtin_popcountll
#define gc getchar_unlocked
#define pc putchar_unlocked
#define pb push_back
#define pf push_front
#define rf pop_front
#define rb pop_back
#define mp make_pair
#define fs first
#define sc second
#define fi ios_base::sync_with_stdio(false); cin.tie(NULL)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll M = 1e9 + 7;
const ll INF = 1e9;

inline ll pwr(ll base,ll n,ll m){ll ans=1;while(n>0){if(n%2==1)ans=(ans*base)%m;base=(base*base)%m;n/=2;}return ans;}

const int sz = (int)1e5 + 2;
int n, m, w, a, b;
vector< map<int,int> > rec;

int Less_Than( int v, int wt ) {

    map<int,int>::iterator it = rec[a].lower_bound(w);

    if( it == rec[a].begin() ) return 0;
    it--;
    return ((*it).sc);

}

int main() {
    fi;

    cin>>n>>m;
    int ans = 0;
    rec.resize(n+1);
    while(m--) {

        cin>>a>>b>>w;

        int endingAtA = Less_Than( w, a );
        int endingAtB = Less_Than( w+1, b );

        if( endingAtB > endingAtA + 1 )
            continue;
        rec[b][w] = endingAtA + 1;
        // Remove records where
        // count of ( endingAtB with weight > w )
        // is less than count of ( endingAtB with weight = w )
        map<int,int>::iterator it = rec[b].upper_bound(w);

        do {
            if( it != rec[b].end() && (*it).sc < endingAtA + 1 ) {
                rec[b].erase(it);
                it = rec[b].upper_bound(w);
            }
        } while( it != rec[b].end() && (*it).sc < endingAtA + 1 );

        ans = max(ans,endingAtA + 1);
    }

    cout<<ans;

    return 0;
}


#include <bits/stdc++.h>

#define loop(i,n)    for( int i=0; i<n; i++ )
#define loop1(i,a,n) for( int i=a; i<n; i++ )
#define vloop(i,a)   for( vector<ll>::iterator i=a.begin(); i!=a.end(); i++ )
#define dloop(i,a)   for( deque<char>::iterator i=a.begin(); i!=a.end(); i++ )
#define PI 3.14159265
#define bc __builtin_popcountll
#define gc getchar_unlocked
#define pc putchar_unlocked
#define pb push_back
#define pf push_front
#define rf pop_front
#define rb pop_back
#define mp make_pair
#define fs first
#define sc second
#define fi ios_base::sync_with_stdio(false); cin.tie(NULL)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll M = 1e9 + 7;
const ll INF = 1e9;

inline ll pwr(ll base,ll n,ll m){ll ans=1;while(n>0){if(n%2==1)ans=(ans*base)%m;base=(base*base)%m;n/=2;}return ans;}

const int sz = (int)1e5 + 2;
vector< pair< int, pair<int, int> > > adj[sz];
int n, m, w, a, b;
int dp[sz];

int dfs( int curr, int rnk, int Wpre, int cnt ) {

    if( rnk != 0 && dp[rnk] != -1 )
        return cnt + dp[rnk];

    int ans = cnt;

    for( vector< pair< int, pair<int, int> > >::iterator it = adj[curr].begin(); it != adj[curr].end(); it++ ) {

        int r = (*it).sc.sc;
        int w = (*it).sc.fs;
        int v = (*it).fs;

        if( r > rnk && w > Wpre ) {
            ans = max( ans, dfs( v, r, w, cnt + 1 ) );
        }

    }
    if( rnk != 0 )
        dp[rnk] = ans - cnt;
    return ans;

}

int main() {
    fi;

    cin>>n>>m;
    memset(dp,-1,sizeof(dp));
    loop(i,m) {
        cin>>a>>b>>w;
        adj[a].pb(mp(b,mp(w,i+1)));
        adj[b].pb(mp(a,mp(w,i+1)));
    }

    int ans = 0;
    loop(i,n) {
        ans = max(ans, dfs(i+1,0,-1,0) );
    }
    cout<<ans;
    return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn], et[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	assert(c1 == 0 && c2 == 0);
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void cdq(int ql, int qr, int l, int r) {
	if (ql >= qr || l >= r) return;

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

	divide(ql, qr, mid, c1, c2);

	cdq(ql + c1, qr, mid + 1, r);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];

	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	for (int i = qr; i >= ql; i--) if (e[i].w > mid) ans[e[i].a] = 0;

	divide(ql, qr, mid, c1, c2);

	cdq(ql, ql + c1 - 1, l, mid);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn], et[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	assert(c1 == 0 && c2 == 0);
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l >= r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

//	puts("===");
//	pr(ql, qr);
//	puts("===");

	divide(ql, qr, mid, c1, c2);

	assert(c1 + c2 == qr - ql + 1);

	cdq(ql + c1, qr, mid + 1, r);

	//sort(e + ql, e + qr + 1, cmp1);

//	puts("---");
//	pr(ql, qr);
//	puts("---");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);
	assert(c1 + c2 == qr - ql + 1);
	cdq(ql, ql + c1 - 1, l, mid);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);
	sort(e + 1, e + 1 + m, cmp1);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	assert(c1 == 0 && c2 == 0);
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l >= r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

//	puts("===");
//	pr(ql, qr);
//	puts("===");

	divide(ql, qr, mid, c1, c2);

	assert(c1 + c2 == qr - ql + 1);

	cdq(ql + c1, qr, mid + 1, r);
	sort(e + ql, e + qr + 1, cmp1);

//	puts("---");
//	pr(ql, qr);
//	puts("---");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);
	assert(c1 + c2 == qr - ql + 1);
	cdq(ql, ql + c1 - 1, l, mid);
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);
	sort(e + 1, e + 1 + m, cmp1);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn], et[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {

	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l >= r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

	divide(ql, qr, mid, c1, c2);

	cdq(ql + c1, qr, mid + 1, r);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];

//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);

	cdq(ql, ql + c1 - 1, l, mid);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];
//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);

	sort(e + 1, e + 1 + m, cmp1);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn], et[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {

	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l >= r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

	divide(ql, qr, mid, c1, c2);

	cdq(ql + c1, qr, mid + 1, r);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];

//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);

	cdq(ql, ql + c1 - 1, l, mid);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];
//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	assert(c1 == 0 && c2 == 0);
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l > r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

//	puts("===");
//	pr(ql, qr);
//	puts("===");

	divide(ql, qr, mid, c1, c2);

	assert(c1 + c2 == qr - ql + 1);

	cdq(ql + c1, qr, mid + 1, r);
	sort(e + ql, e + qr + 1, cmp1);

//	puts("---");
//	pr(ql, qr);
//	puts("---");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);
	assert(c1 + c2 == qr - ql + 1);
	cdq(ql, ql + c1 - 1, l, mid);
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);
	sort(e + 1, e + 1 + m, cmp1);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	assert(c1 == 0 && c2 == 0);
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l > r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

//	puts("===");
//	pr(ql, qr);
//	puts("===");

	divide(ql, qr, mid, c1, c2);

	assert(c1 + c2 == qr - ql + 1);

	cdq(ql + c1, qr, mid + 1, r);
	sort(e + ql, e + qr + 1, cmp1);

//	puts("---");
//	pr(ql, qr);
//	puts("---");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);
	assert(c1 + c2 == qr - ql + 1);
	cdq(ql, ql + c1 - 1, l, mid);
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 10);
	sort(e + 1, e + 1 + m, cmp1);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn];
bool cmp(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void sol(int ql, int qr, int l, int r) {
	if (ql >= qr || l >= r) return;
	int mid = (l + r) >> 1;

	int c1 = 0, c2 = 0;
	divide(ql, qr, mid, c1, c2);
	sol(ql + c1, qr, mid + 1, r);
	inplace_merge(e + ql, e + ql + c1, e + qr + 1, cmp);

	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);
	for (int i = qr; i >= ql; i--)
		if (e[i].w > mid) ans[e[i].a] = 0;

	c1 = c2 = 0;
	divide(ql, qr, mid, c1, c2);
	sol(ql, ql + c1 - 1, l, mid);
	inplace_merge(e + ql, e + ql + c1, e + qr + 1, cmp);
}

int main() {
#ifdef AC
    freopen("data.in", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	sol(1, m, 0, 1e5);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	printf("%d\n", out);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn], et[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {

	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l >= r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

	divide(ql, qr, mid, c1, c2);

	cdq(ql + c1, qr, mid + 1, r);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];

//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);

	cdq(ql, ql + c1 - 1, l, mid);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];
//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);

	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
struct edge {
	int id, a, b, w, ans;
	void in(int i) {
		id = i;
		scanf("%d%d%d", &a, &b, &w);
		this->ans = 1;
	}
	void out() {
		printf("%d: a=%d,b=%d,w=%d,ans=%d\n", id, a, b, w, ans);
	}
}e[maxn], e1[maxn], e2[maxn], et[maxn];
bool cmp1(const edge &e1, const edge &e2) {
	return e1.id < e2.id;
}
bool cmp2(const edge &e1, const edge &e2) {
	return e1.w < e2.w;
}

void divide(int ql, int qr, int mid, int &c1, int &c2) {
	assert(c1 == 0 && c2 == 0);
	for (int i = ql; i <= qr; i++) {
		if (e[i].w <= mid) e1[c1++] = e[i];
		else e2[c2++] = e[i];
	}
	for (int i = 0; i < c1; i++) e[ql + i] = e1[i];
	for (int i = 0; i < c2; i++) e[ql + c1 + i] = e2[i];
}

int ans[maxn];

void pr(int ql, int qr) {
	for (int i = ql; i <= qr; i++) e[i].out();
}
void cdq(int ql, int qr, int l, int r) {

//	printf("ST[%d,%d] [%d,%d]\n", ql, qr, l, r);
	if (ql >= qr || l >= r) {
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
		return;
	}

	int mid = (l + r) >> 1;
	int c1 = 0, c2 = 0;

	divide(ql, qr, mid, c1, c2);

	assert(c1 + c2 == qr - ql + 1);

	cdq(ql + c1, qr, mid + 1, r);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];

//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");

	for (int i = 1; i <= n; i++) ans[i] = 0;
	c1 = c2 = 0;
	for (int i = qr; i >= ql; i--)
		if (e[i].w <= mid) cmax(e[i].ans, ans[e[i].b] + 1);
		else  cmax(ans[e[i].a], e[i].ans);

	divide(ql, qr, mid, c1, c2);

	assert(c1 + c2 == qr - ql + 1);

	cdq(ql, ql + c1 - 1, l, mid);
	merge(e + ql, e + ql + c1, e + ql + c1, e + qr + 1, et + ql, cmp1);
	for (int i = ql; i <= qr; i++) e[i] = et[i];
//	puts("==");
//	for (int i = ql; i <= qr; i++) e[i].out();
//	puts("==");
//	printf("ED[%d,%d] [%d,%d]\n", ql, qr, l, r);
}

int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++) e[i].in(i);
	cdq(1, m, 0, 1e5);

	sort(e + 1, e + 1 + m, cmp1);
	int out = 0;
	for (int i = 1; i <= m; i++) cmax(out, e[i].ans);
	cout << out << endl;
	//for (int i = 1; i <= m; i++) printf("%d\n", e[i].ans);
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
vector<int> eg[maxn], g[maxn], ng[maxn];
struct edge {
	int a, b, w;
	void in() {
		scanf("%d%d%d", &a, &b, &w);
	}
}e[maxn];

int dis[maxn];
int sol(int i) {
	if (dis[i] != -1) return dis[i];
	int ret = 0;

	for (auto x : eg[e[i].b]) {
		if (x > i && e[x].w > e[i].w) {
			cmax(ret, sol(x));
		}
	}

	return dis[i] = ret + 1;
}
int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) e[i].in(), eg[e[i].a].pb(i);
//	for (int i = 0; i < m; i++) {
//		for (auto x : eg[e[i].b]) if (x > i && e[x].w > e[i].w) ng[i].pb(x);
//	}
//	for (int i = 0; i < m; i++)
//		for (auto v : ng[i]) printf("%d->%d\n", i + 1, v + 1);
	clr(dis, -1);
	dis[m - 1] = 1;
	int ans = 0;
	for (int i = 0; i < m; i++)
		cmax(ans, sol(i));
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>

#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define all(x) (x).begin(), (x).end()
#define sqr(x) ((x) * (x))
#define clr(a,b) (memset(a,b,sizeof(a)))
#define y0 y3487465
#define y1 y8687969
#define fastio std::ios::sync_with_stdio(false)
#define cmin(a, b) ((a) = ((a) < (b) ? (a) : (b)))
#define cmax(a, b) ((a) = ((a) > (b) ? (a) : (b)))

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

const int inf = 1e9 + 7;
const int mod = 1e9 + 7;
const int maxn = 1e5 + 7;

int n, m, k;
vector<int> eg[maxn], g[maxn], ng[maxn];
int v[maxn];
struct edge {
	int a, b, w;
	void in() {
		scanf("%d%d%d", &a, &b, &w);
	}
}e[maxn];

int dis[maxn];
int sol(int x) {
	if (dis[x] != -1) return dis[x];
	int ret = 0;
	for (auto v : ng[x]) {
		cmax(ret, sol(v));
	}
	return dis[x] = ret + 1;
}
int main() {
#ifdef AC
    freopen("data.txt", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; i++) e[i].in(), eg[e[i].a].pb(i);
	for (int i = 0; i < m; i++) {
		v[i] = e[i].w;
		for (auto x : eg[e[i].b]) if (x > i && e[x].w > e[i].w) ng[i].pb(x);
	}
//	for (int i = 0; i < m; i++)
//		for (auto v : ng[i]) printf("%d->%d\n", i + 1, v + 1);
	clr(dis, -1);
	dis[m - 1] = 1;
	int ans = 0;
	for (int i = 0; i < m; i++)
		cmax(ans, sol(i));
	cout << ans << endl;
	return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
//int query(int o,int l,int r,int x)
//{
//   if(l==r||r<=x)return tr[o].mx;
//   if(l>x)return 0;
//   int m=(l+r)>>1;
//   int ans=0;
//   ans=max(ans,query(tr[o].l,l,m,x));
//   ans=max(ans,query(tr[o].r,m+1,r,x));
//   return ans;
//}
int query(int k,int l,int r,int x){
    if(l==r)return tr[k].mx;
    int mid=(l+r)>>1;
    if(x<=mid)return query(tr[k].l,l,mid,x);
    else return max(tr[tr[k].l].mx,query(tr[k].r,mid+1,r,x));
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans;
bool vis[maxn];
struct node{int u,v,len;}da[maxn];
struct edge
{
    int to,len,id;
};
vector<edge> g[maxn];
void dfs(int v,int d,int la)
{
    //cout<<"TTT"<<v<<" "<<d<<" "<<la<<endl;
    ans=max(ans,d);
    //vis[v]=true;
   // cout<<g[v].size()<<endl;
    for(edge to:g[v])
    {
       // cout<<to.id<<" "<<la<<" "<<to.len<<" "<<da[la].len<<" "<<endl;
        if(to.id>la&&to.len>da[la].len)
        {
            dfs(to.to,d+1,to.id);
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>da[i].u>>da[i].v>>da[i].len;
        edge tmp;tmp.id=i;tmp.len=da[i].len;tmp.to=da[i].v;
        g[da[i].u].pb(tmp);
    }
    da[0].len=0;da[0].u=0;da[0].v=0;
    for(int i=1;i<=m;i++)
    {
        if(!vis[da[i].u])
        {
          //  cout<<"*****"<<endl;
            dfs(da[i].u,0,0);
         //   cout<<"*****"<<endl;
        }
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
int query(int o,int l,int r,int x)
{
   if(l==r)return tr[o].mx;
   if(l>x)return 0;
   int mid=(l+r)>>1;
   int ans=0;
   if(x<=mid)return query(tr[o].l,l,mid,x);
   else return max(tr[tr[o].l].mx,query(tr[o].r,mid+1,r,x));
}
//int query(int k,int l,int r,int x){
//    if(l==r)return tr[k].mx;
//    int mid=(l+r)>>1;
//    if(x<=mid)return query(tr[k].l,l,mid,x);
//    else return max(tr[tr[k].l].mx,query(tr[k].r,mid+1,r,x));
//}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
int query(int o,int l,int r,int x)
{
   if(r<=x)return tr[o].mx;
   if(l>x)return 0;
   int mid=(l+r)>>1;
   int ans=0;
   if(x<=mid)return query(tr[o].l,l,mid,x);
   else return max(tr[tr[o].l].mx,query(tr[o].r,mid+1,r,x));
}
//int query(int k,int l,int r,int x){
//    if(l==r)return tr[k].mx;
//    int mid=(l+r)>>1;
//    if(x<=mid)return query(tr[k].l,l,mid,x);
//    else return max(tr[tr[k].l].mx,query(tr[k].r,mid+1,r,x));
//}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans;
bool vis[maxn];
int dp[maxn];
struct node{int u,v,len;}da[maxn];
struct edge
{
    int to,len,id;
};
vector<edge> g[maxn];
bool judge(int x,int la)
{
    for(edge to:g[x])
    {
        if(to.id>la&&to.len>da[la].len)
        {
            return true;
        }
    }return false;
}
void dfs(int v,int d,int la)
{
   // cout<<"TTT"<<v<<" "<<d<<" "<<la<<endl;
    if(!judge(v,la))
    {
        dp[v]=0;return ;
    }
    for(edge to:g[v])
    {
       // cout<<to.id<<" "<<la<<" "<<to.len<<" "<<da[la].len<<" "<<endl;
        if(to.id>la&&to.len>da[la].len)
        {
            if(dp[to.to]!=-1)
            {
                dp[v]=max(dp[v],dp[to.to]+1);
                return ;
            }
            else
            {
                dfs(to.to,d+1,to.id);
                dp[v]=max(dp[v],dp[to.to]+1);
            }
        }
    }
}
void view()
{
    for(int i=1;i<=n;i++)
    {
        cout<<dp[i]<<" ";
    }cout<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>da[i].u>>da[i].v>>da[i].len;
        edge tmp;tmp.id=i;tmp.len=da[i].len;tmp.to=da[i].v;
        g[da[i].u].pb(tmp);
    }
    memset(dp,-1,sizeof(dp));
    da[0].len=0;da[0].u=0;da[0].v=0;
    for(int i=1;i<=m;i++)
    {
        if(dp[da[i].u]==-1)
        {
            ans=da[i].u;
            //cout<<"*****"<<endl;
            dfs(da[i].u,0,0);
            //cout<<"*****"<<endl;
           // view();
        }
    }
    ll an=0;
    for(int i=1;i<=n;i++)an=max(an,1ll*dp[i]);
    cout<<an<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
int query(int o,int l,int r,int x)
{
   if(l==r||r<=x)return tr[o].mx;
   if(l>x)return 0;
   int m=(l+r)>>1;
   int ans=0;
   ans=max(ans,query(tr[o].l,l,m,x));
   ans=max(ans,query(tr[o].r,m+1,r,x));
   return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans;
bool vis[maxn];
int dp[maxn];
struct node{int u,v,len;}da[maxn];
struct edge
{
    int to,len,id;
};
vector<edge> g[maxn];
void dfs(int v,int d,int la)
{
   // cout<<"TTT"<<v<<" "<<d<<" "<<la<<endl;
    dp[ans]=max(dp[ans],d);

    for(edge to:g[v])
    {
       // cout<<to.id<<" "<<la<<" "<<to.len<<" "<<da[la].len<<" "<<endl;
        if(to.id>la&&to.len>da[la].len)
        {
            if(dp[to.to]!=-1)
            {
                dp[v]=max(dp[v],dp[to.to]+d+1);
                return ;
            }
            else
            {
                dfs(to.to,d+1,to.id);
                dp[v]=max(dp[v],dp[to.to]+d+1);
                dp[to.to]=max(dp[to.to],dp[ans]-d-1);
            }
        }
    }
}
void view()
{
    for(int i=1;i<=n;i++)
    {
        cout<<dp[i]<<" ";
    }cout<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>da[i].u>>da[i].v>>da[i].len;
        edge tmp;tmp.id=i;tmp.len=da[i].len;tmp.to=da[i].v;
        g[da[i].u].pb(tmp);
    }
    memset(dp,-1,sizeof(dp));
    da[0].len=0;da[0].u=0;da[0].v=0;
    for(int i=1;i<=m;i++)
    {
        if(dp[da[i].u]==-1)
        {
            ans=da[i].u;
          //  cout<<"*****"<<endl;
            dfs(da[i].u,0,0);
           // cout<<"*****"<<endl;
            //view();
        }
    }
    ll an=0;
    for(int i=1;i<=n;i++)an=max(an,1ll*dp[i]);
    cout<<an<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
int query(int o,int l,int r,int x)
{
   if(r<=x)return tr[o].mx;
   if(l>x)return 0;
   int mid=(l+r)>>1;
   int ans=0;
   ans=max(ans,query(tr[o].l,l,mid,x));
   ans=max(ans,query(tr[o].r,mid+1,r,x));
   return ans;
}
//int query(int k,int l,int r,int x){
//    if(l==r)return tr[k].mx;
//    int mid=(l+r)>>1;
//    if(x<=mid)return query(tr[k].l,l,mid,x);
//    else return max(tr[tr[k].l].mx,query(tr[k].r,mid+1,r,x));
//}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
int query(int o,int l,int r,int x)
{
   if(r<x||l==r)return tr[o].mx;
   //if(l>x)return 0;
   int mid=(l+r)>>1;
   if(x<=mid)return query(tr[o].l,l,mid,x);
   else return max(tr[tr[o].l].mx,query(tr[o].r,mid+1,r,x));
}
//int query(int k,int l,int r,int x){
//    if(l==r)return tr[k].mx;
//    int mid=(l+r)>>1;
//    if(x<=mid)return query(tr[k].l,l,mid,x);
//    else return max(tr[tr[k].l].mx,query(tr[k].r,mid+1,r,x));
//}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include<bits/stdc++.h>
#include<set>
#include<cstdio>
#include<iomanip>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#define pb push_back
#define ll long long
#define fi first
#define se second
#define PI 3.14159265
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define eps 1e-7
#define pii pair<int,int>
typedef unsigned long long ull;
using namespace std;
const int mod=1e3+5;
const ll inf=0x3f3f3f3f3f3f3f;
const int maxn=1e5+5;
int n,m,ans,cnt;
int f[maxn],rt[maxn];
struct tree{int l,r,mx;}tr[maxn*20];
void insert(int &o,int l,int r,int x,int y)
{
    if(!o)o=++cnt;tr[o].mx=max(tr[o].mx,y);
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(x<=mid)insert(tr[o].l,l,mid,x,y);
    else insert(tr[o].r,mid+1,r,x,y);
}
int query(int o,int l,int r,int x)
{
   if(r<x)return tr[o].mx;
   //if(l>x)return 0;
   int mid=(l+r)>>1;
   int ans=0;
   if(x<=mid)return query(tr[o].l,l,mid,x);
   else return max(tr[tr[o].l].mx,query(tr[o].r,mid+1,r,x));
}
//int query(int k,int l,int r,int x){
//    if(l==r)return tr[k].mx;
//    int mid=(l+r)>>1;
//    if(x<=mid)return query(tr[k].l,l,mid,x);
//    else return max(tr[tr[k].l].mx,query(tr[k].r,mid+1,r,x));
//}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=0;i<m;i++)
    {
        int u,v,w;
        cin>>u>>v>>w;
        f[i]=query(rt[u],1,1e5,w-1)+1;
        insert(rt[v],1,1e5,w,f[i]);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAXV (1 << 30)
#define MAX_N (1 << 18)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        ans[b] = max(ans[b], BT[a].query(0, c, 0, MAXV) + 1);
        BT[b].add(c, ans[b], 0, MAXV);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAX_N (1 << 20)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];
map<int, int> mp[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        ans[b] = max(ans[b], BT[a].query(0, c + 1, 0, MAX_N) + 1);
        BT[b].add(c + 1, ans[b], 0, MAX_N);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAX_N (1 << 20)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c, nt;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        nt = BT[a].query(0, c + 1, 0, MAX_N) + 1;

        ans[b] = max(ans[b], nt);
        BT[b].add(c + 1, nt, 0, MAX_N);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAXV (1 << 30)
#define MAX_N (1 << 17)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        ans[b] = max(ans[b], BT[a].query(0, c + 1, 0, MAXV) + 1);
        BT[b].add(c + 1, ans[b], 0, MAXV);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAX_N (1 << 20)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        ans[b] = max(ans[b], BT[a].query(0, c + 1, 0, MAX_N) + 1);
        BT[b].add(c + 1, ans[b], 0, MAX_N);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAX_N (1 << 17)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        ans[b] = max(ans[b], BT[a].query(0, c + 1, 0, MAX_N) + 1);
        BT[b].add(c + 1, ans[b], 0, MAX_N);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>

using namespace std;

#define MAX_N (1 << 20)
#define MAX_T 230005

#define f first
#define s second

struct node {
  int val;
  struct node* C[2];

  node() {
    val = 0;
    C[0] = C[1] = NULL;
  }

  node* getc(int c) {
    if (!C[c]) {
      C[c] = new node;
    }
    return C[c];
  }

  void add(int x, int v, int lo, int hi) {
    val = max(val, v);
    if (hi - lo == 1) {
      return;
    }
    int md = (lo + hi) / 2;
    if (x < md) {
      getc(0)->add(x, v, lo, md);
    } else {
      getc(1)->add(x, v, md, hi);
    }
  }

  int query(int a, int b, int lo, int hi) {
    if (a <= lo && hi <= b) {
      return val;
    } else if (hi <= a || b <= lo) {
      return 0;
    }
    int md = (lo + hi) / 2;
    return max((C[0] ? C[0]->query(a, b, lo, md) : 0),
               (C[1] ? C[1]->query(a, b, md, hi) : 0));
  }
};

node BT[MAX_N];

int ans[MAX_N];
int N, M;

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

    int a, b, c;
    for (int i = 0; i < M; i ++) {
        cin >> a >> b >> c;
        a --; b --;

        nt = BT[a].query(0, c + 1, 0, MAX_N) + 1;

        ans[b] = max(ans[b], nt);
        BT[b].add(c + 1, nt, 0, MAX_N);
    }

    int final = 0;
    for (int i = 0; i < N; i ++)
        final = max(final, ans[i]);

    cout << final << endl;
    return (0);
}


#include <iostream>
#include <cstdio>
#define N 100002
using namespace std;
struct node{
	int l,r,dat;
}t[N*40];
int n,m,i,f[N],root[N],cnt,ans;
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
void change(int &p,int l,int r,int x,int val)
{
	if(p==0) p=++cnt;
	if(l==r){
		t[p].dat=val;
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid) change(t[p].l,l,mid,x,val);
	else change(t[p].r,mid+1,r,x,val);
	t[p].dat=max(t[t[p].l].dat,t[t[p].r].dat);
}
int ask(int p,int l,int r,int ql,int qr)
{
	if(p==0) return 0;
	if(ql<=l&&r<=qr) return t[p].dat;
	int mid=(l+r)/2,ans=0;
	if(ql<=mid) ans=max(ans,ask(t[p].l,l,mid,ql,qr));
	if(qr>mid) ans=max(ans,ask(t[p].r,mid+1,r,ql,qr));
	return ans;
}
int main()
{
	n=read();m=read();
	for(i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		f[v]=ask(root[u],0,100000,1,w-1)+1;
		ans=max(ans,f[v]);
		change(root[v],0,100000,w,f[v]);
	}
	printf("%d\n",ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#define N 100002
using namespace std;
struct node{
	int l,r,dat;
}t[N*40];
int n,m,i,f[N],root[N],cnt,ans;
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
void change(int &p,int l,int r,int x,int val)
{
	if(p==0) p=++cnt;
	if(l==r){
		t[p].dat=val;
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid) change(t[p].l,l,mid,x,val);
	else change(t[p].r,mid+1,r,x,val);
	t[p].dat=max(t[t[p].l].dat,t[t[p].r].dat);
}
int ask(int p,int l,int r,int ql,int qr)
{
	if(p==0) return 0;
	if(ql<=l&&r<=qr) return t[p].dat;
	int mid=(l+r)/2,ans=0;
	if(ql<=mid) ans=max(ans,ask(t[p].l,l,mid,ql,qr));
	if(qr>mid) ans=max(ans,ask(t[p].r,mid+1,r,ql,qr));
	return ans;
}
int main()
{
	n=read();m=read();
	for(i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		f[v]=ask(root[u],1,100000,1,w-1)+1;
		ans=max(ans,f[v]);
		change(root[v],1,100000,w,f[v]);
	}
	printf("%d\n",ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#define N 100002
using namespace std;
struct node{
	int l,r,dat;
}t[N*40];
int n,m,i,f[N],root[N],cnt;
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
void change(int &p,int l,int r,int x,int val)
{
	if(p==0) p=++cnt;
	if(l==r){
		t[p].dat=val;
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid) change(t[p].l,l,mid,x,val);
	else change(t[p].r,mid+1,r,x,val);
	t[p].dat=max(t[t[p].l].dat,t[t[p].r].dat);
}
int ask(int p,int l,int r,int ql,int qr)
{
	if(p==0) return 0;
	if(ql<=l&&r<=qr) return t[p].dat;
	int mid=(l+r)/2,ans=0;
	if(ql<=mid) ans=max(ans,ask(t[p].l,l,mid,ql,qr));
	if(qr>mid) ans=max(ans,ask(t[p].r,mid+1,r,ql,qr));
	return ans;
}
int main()
{
	n=read();m=read();
	for(i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		f[v]=ask(root[u],1,100000,1,w-1)+1;
		change(root[v],1,100000,w,f[v]);
	}
	int ans=0;
	for(i=1;i<=n;i++) ans=max(ans,f[i]);
	printf("%d\n",ans);
	return 0;
}


#include <iostream>
#include <cstdio>
#define N 100002
using namespace std;
struct node{
	int l,r,dat;
}t[N*40];
int n,m,i,f[N],root[N],cnt,ans;
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
void change(int &p,int l,int r,int x,int val)
{
	if(p==0) p=++cnt;
	if(l==r){
		t[p].dat=val;
		return;
	}
	int mid=(l+r)/2;
	if(x<=mid) change(t[p].l,l,mid,x,val);
	else change(t[p].r,mid+1,r,x,val);
	t[p].dat=max(t[t[p].l].dat,t[t[p].r].dat);
}
int ask(int p,int l,int r,int ql,int qr)
{
	if(p==0) return 0;
	if(ql<=l&&r<=qr) return t[p].dat;
	int mid=(l+r)/2,ans=0;
	if(ql<=mid) ans=max(ans,ask(t[p].l,l,mid,ql,qr));
	if(qr>mid) ans=max(ans,ask(t[p].r,mid+1,r,ql,qr));
	return ans;
}
int main()
{
	n=read();m=read();
	for(i=1;i<=m;i++){
		int u=read(),v=read(),w=read()+1;
		f[v]=ask(root[u],1,100000,1,w-1)+1;
		ans=max(ans,f[v]);
		change(root[v],1,100000,w,f[v]);
	}
	printf("%d\n",ans);
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        if(iter2!=G[v1[i]].begin())
        {
            while(true)
            {
                if(iter2==G[v1[i]].begin())break;
                else iter2--;
                dp[i] = max(dp[i], dp[iter2->e]+1);

            }
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        for(auto e:G[v1[i]])
        {
            if(e.w>w[i])
            {
                break;
            }

            if(e.w<w[i])
            {
                if(dp[i]<dp[e.e]+1)
                {
                    dp[i]=dp[e.e]+1;
                }
            }
        }
        G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        if(iter2!=G[v1[i]].begin())
        {
            int i=0;
            while(true)
            {
                if(iter2==G[v1[i]].begin())break;
                else iter2--;
                dp[i] = max(dp[i], dp[iter2->e]+1);
                i++;
                if(i>10)break;
            }
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        if(iter2!=G[v1[i]].begin())
        {
            int i=0;
            while(true)
            {
                if(iter2==G[v1[i]].begin())break;
                else iter2--;
                dp[i] = max(dp[i], dp[iter2->e]+1);
                i++;
                if(i>3)break;
            }
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        for(auto e:G[v1[i]])
        {
            if(e.w>w[i])
            {
                break;
            }

            if(e.w<w[i])
            {
                if(dp[i]<dp[e.e]+1)
                {
                    dp[i]=dp[e.e]+1;
                }
            }
        }

        // auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        // if(iter2!=G[v1[i]].begin())
        // {
        //     iter2--;
        //     dp[i] = dp[iter2->e]+1;
        // }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n,m;
map<int,int> mc[100000+100];

//此函数配合lowerbound，做出的是关于w的什么效果？ 就是找比w小的最长链（而不是找以w为结尾的最长链）
int get(int x,int w)
{
	 auto it = mc[x].lower_bound(w);
	 if(it==mc[x].begin())return 0;
	 it--;
	 return it->second;
}

int main()
{
	ios::sync_with_stdio(false);
	cin>>n>>m;
	int ans = 0;
	for(int i=0;i<m;i++)
	{
		int a,b,w;
		cin>>a>>b>>w;
		int len = get(a,w);
		if(len<get(b,w+1))continue;
		mc[b][w]=len+1;
		auto it = mc[b].upper_bound(w);
		//LIS注意点，更新时需要考虑删除
		while(it!=mc[b].end()&&it->second<=len+1)
		{
			it = mc[b].erase(it);
		}
		ans = max(ans,len+1);
	}
	cout<<ans<<endl;

}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        if(iter2!=G[v1[i]].begin())
        {
            iter2--;
            dp[i] = dp[iter2->e]+1;
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        if(iter2!=G[v1[i]].begin())
        {
            int k=0;
            while(true)
            {
                if(iter2==G[v1[i]].begin())break;
                else iter2--;
                dp[i] = max(dp[i], dp[iter2->e]+1);
                // k++;
                // if(k>10)break;
            }
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        //这里LIS原本写漏了，没有考虑w比当前小的他的dp值，又是考虑后端，忘了考虑前端。
        if(iter!=G[v1[i]].begin())
        {
            auto iter3 = iter;
            iter3--;
            if(dp[iter3->e]>=dp[i])continue;
        }
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)return dp[e]<dp[rhs.e];
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // int down = 0,up = i;
        // while(down<up)
        // {
        //     int mid = (down+up)/2;
        //     auto iter = G[v1[i]].find(mid);
        //     if(iter==G)
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],0});
        if(iter2!=G[v1[i]].begin())
        {
            iter2--;
            dp[i] = dp[iter2->e]+1;
        }

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],0});
        if(iter==G[v1[i]].end()||iter->w>w[i]||( iter->w==w[i]&&dp[iter->e]<=dp[i]))
        {
            while(true)
            {
                if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
                {
                    iter = G[v1[i]].erase(iter);
                }else{
                    break;
                }
            }
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
        }

    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)return dp[e]<dp[rhs.e];
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],0});
        if(iter2!=G[v1[i]].begin())
        {
            iter2--;
            dp[i] = dp[iter2->e]+1;
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],0});
        int flag=0;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)return dp[e]<dp[rhs.e];
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // int down = 0,up = i;
        // while(down<up)
        // {
        //     int mid = (down+up)/2;
        //     auto iter = G[v1[i]].find(mid);
        //     if(iter==G)
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],0});
        if(iter2!=G[v1[i]].begin())
        {
            iter2--;
            dp[i] = dp[iter2->e]+1;
        }

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],0});
        if(iter==G[v1[i]].end()||iter->w>w[i]||( iter->w==w[i]&&dp[iter->e]<dp[i]))
        {
            while(true)
            {
                if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
                {
                    iter = G[v1[i]].erase(iter);
                }else{
                    break;
                }
            }
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
        }

    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)return dp[e]<dp[rhs.e];
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        for(auto e:G[v1[i]])
        {
            if(e.w>w[i])
            {
                break;
            }

            if(e.w<w[i])
            {
                if(dp[i]<dp[e.e]+1)
                {
                    dp[i]=dp[e.e]+1;
                }
            }
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],0});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxm = 100000+100;

int dp[maxm];
struct Edge
{
    int u,v,w,e;
    bool operator< (const Edge &rhs)const{
        if(w==rhs.w)
        {
            return (e==-1?-1:dp[e])< (rhs.e==-1?-1:dp[rhs.e]);
        }
        return w<rhs.w;
    }
};

int n,m;
int v1[maxm],v2[maxm],w[maxm];
set<Edge> G[100000+100];
int dpG[100000+100];

int main()
{
    //freopen("I:\\Project\\acm\\Algorithm\\input.txt","r",stdin);//

    ios::sync_with_stdio(false);
    fill(begin(dp),end(dp),1);
    cin>>n>>m;
    for (int i = 0; i < m; i++) {
        cin>>v1[i]>>v2[i]>>w[i];

        // for(auto e:G[v1[i]])
        // {
        //     if(e.w>w[i])
        //     {
        //         break;
        //     }
        //
        //     if(e.w<w[i])
        //     {
        //         if(dp[i]<dp[e.e]+1)
        //         {
        //             dp[i]=dp[e.e]+1;
        //         }
        //     }
        // }

        auto iter2 = G[v1[i]].lower_bound({0,0,w[i],-1});
        if(iter2!=G[v1[i]].begin())
        {
            int k=0;
            while(true)
            {
                if(iter2==G[v1[i]].begin())break;
                else iter2--;
                dp[i] = max(dp[i], dp[iter2->e]+1);
                k++;
                if(k>10)break;
            }
        }

        auto iter = G[v1[i]].lower_bound({0,0,w[i],-1});
        int flag=0;
        if(iter== G[v1[i]].end()|| iter->w>w[i])flag=1;
        //这里LIS原本写漏了，没有考虑w比当前小的他的dp值，又是考虑后端，忘了考虑前端。
        if(iter!=G[v1[i]].begin())
        {
            auto iter3 = iter;
            iter3--;
            if(dp[iter3->e]>=dp[i])continue;
        }
        while(true)
        {
            if(iter!=G[v1[i]].end()&& iter->w>=w[i]&&dp[iter->e]<=dp[i])
            {
                iter = G[v1[i]].erase(iter);
                flag=1;
            }else{
                break;
            }
        }
        if(flag==1)
            G[v2[i]].insert({v1[i],v2[i],w[i],i});
    }
    int ans=0;
    for(int i=0;i<m;i++)
    {
        if(ans<dp[i])ans=dp[i];
    }
    cout<<ans<<endl;

    return 0;
}