#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
inline int read() {
  int x = 0, f = 1;
  char c = getchar();
  while (c < '0' || c > '9') {
    if (c == '-') f = -1;
    c = getchar();
  }
  while (c >= '0' && c <= '9') {
    x = x * 10 + c - '0';
    c = getchar();
  }
  return x * f;
}
int n, m, len = 1e5 + 2;
struct node {
  int maxx;
  int lson, rson;
} tree[N * 32];
int tot = 0;
int root[N];
inline int build_tree(int l, int r) {
  tree[++tot].maxx = 0;
  tree[tot].lson = tree[tot].rson = 0;
  return tot;
}
inline void update(int k) {
  tree[k].maxx = max(tree[tree[k].lson].maxx, tree[tree[k].rson].maxx);
}
inline int query_maxx(int lef, int rig, int &k, int l, int r) {
  if (!k) k = build_tree(lef, rig);
  if (lef >= l && rig <= r) return tree[k].maxx;
  int mid = (lef + rig) >> 1;
  int ans = 0;
  if (l <= mid) ans = max(ans, query_maxx(lef, mid, tree[k].lson, l, r));
  if (r > mid) ans = max(ans, query_maxx(mid + 1, rig, tree[k].rson, l, r));
  update(k);
  return ans;
}
inline void update_val(int lef, int rig, int &k, int l, int r, int val) {
  if (!k) k = build_tree(lef, rig);
  if (lef >= l && rig <= r) {
    tree[k].maxx = max(tree[k].maxx, val);
    return;
  }
  int mid = (lef + rig) >> 1;
  if (l <= mid) update_val(lef, mid, tree[k].lson, l, r, val);
  if (r > mid) update_val(mid + 1, rig, tree[k].rson, l, r, val);
  update(k);
}
int main() {
  int ans = 0;
  n = read();
  m = read();
  int u, v, w;
  for (int i = 1; i <= m; i++) {
    u = read();
    v = read();
    w = read();
    w += 2;
    int val = query_maxx(1, len, root[u], 1, w - 1);
    ans = max(ans, val + 1);
    update_val(1, len, root[v], w, w, val + 1);
  }
  printf("%d\n", ans);
  return 0;
}
