#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 1;
struct TREE {
  int l, r, s;
} t[N * 30];
int tn = 0;
inline void pushup(int u) { t[u].s = max(t[t[u].l].s, t[t[u].r].s); }
inline void update(int &u, int l, int r, int pos, int x) {
  if (!u) u = ++tn;
  if (l == r) {
    t[u].s = max(t[u].s, x);
    return;
  }
  int mid = (l + r) >> 1;
  if (pos <= mid)
    update(t[u].l, l, mid, pos, x);
  else
    update(t[u].r, mid + 1, r, pos, x);
  pushup(u);
}
inline int query(int u, int l, int r, int a, int b) {
  if (a > b || !u) return 0;
  if (a <= l && r <= b) return t[u].s;
  int mid = (l + r) >> 1, res = 0;
  if (a <= mid) res = max(res, query(t[u].l, l, mid, a, b));
  if (b > mid) res = max(res, query(t[u].r, mid + 1, r, a, b));
  return res;
}
int rt[N];
inline int in() {
  int x = 0, f = 1;
  char c = getchar();
  while (c < '0' || c > '9') {
    if (c == '-') f = -1;
    c = getchar();
  }
  while (c >= '0' && c <= '9')
    x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
  return x * f;
}
int main() {
  int n = in(), m = in(), ans = 0;
  for (int i = 1; i <= m; ++i) {
    int u = in(), v = in(), w = in();
    int res = query(rt[u], 1, 1e5, 1, w) + 1;
    ans = max(res, ans);
    update(rt[v], 1, 1e5, w + 1, res);
  }
  printf("%d", ans);
  return 0;
}
