CodeEff/ECCO huggingface dataset:
# Original solution
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# FileName: 	G_fix
# CreatedDate:  2020-06-05 21:28:41 +0900
# LastModified: 2020-06-05 22:03:20 +0900
#


import os
import sys
from collections import deque
#import numpy as np
#import pandas as pd


def main():
    n,m = list(map(int,input().split()))
    path = [[] for _ in range(n+1)]
    to_cnt = [0]*(n+1)
    longest_cnt = [0]*(n+1)
    for _ in range(m):
        x,y = list(map(int,input().split()))
        path[x].append(y)
        to_cnt[y]+=1
    
    Q = deque()
    for i in range(1,n+1):
        if to_cnt[i]==0:
            Q.append(i)

#    longest_cnt[s]=1

    while(Q):
        u = Q.popleft()
        for v in path[u]:
            to_cnt[v]-=1
            if longest_cnt[u]+1>longest_cnt[v]:
                longest_cnt[v]=longest_cnt[u]+1
            Q.append(v)
    print((max(longest_cnt)))



if __name__ == "__main__":
    main()


# Optimized solution
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# FileName: 	G_fix
# CreatedDate:  2020-06-05 21:28:41 +0900
# LastModified: 2020-06-05 22:05:41 +0900
#


import os
import sys
from collections import deque
#import numpy as np
#import pandas as pd


def main():
    n,m = list(map(int,input().split()))
    path = [[] for _ in range(n+1)]
    to_cnt = [0]*(n+1)
    longest_cnt = [0]*(n+1)
    for _ in range(m):
        x,y = list(map(int,input().split()))
        path[x].append(y)
        to_cnt[y]+=1
    
    Q = deque()
    for i in range(1,n+1):
        if to_cnt[i]==0:
            Q.append(i)

#    longest_cnt[s]=1

    while(Q):
        u = Q.popleft()
        for v in path[u]:
            to_cnt[v]-=1
            if longest_cnt[u]+1>longest_cnt[v]:
                longest_cnt[v]=longest_cnt[u]+1
            if to_cnt[v]==0:
                Q.append(v)
    print((max(longest_cnt)))



if __name__ == "__main__":
    main()
# Original solution
N, M = list(map(int, input().split()))
XY = [list(map(int, input().split())) for _ in range(M)]

from collections import defaultdict
from collections import deque
g = defaultdict(set)

for x, y in XY:
  g[x].add(y)

  
def bfs(u):
  s = deque([u])
  cost = {u: 0}
  done = set()
  while s:
    u = s.popleft()
    if u not in done:
      done.add(u)
    else:
      continue
    for v in g[u]:
      cost[v] = cost[u] + 1
      if v in done:
        done.remove(v)
      s.append(v)

  return cost
  
ans = 0
for i in range(1, N+1):
  d = bfs(i)
  ans = max(ans, max(d.values()))
print(ans)

# Optimized solution
N, M = list(map(int, input().split()))
XY = [list(map(int, input().split())) for _ in range(M)]

from collections import defaultdict
from collections import deque
from collections import Counter
g = defaultdict(set)

for x, y in XY:
  g[x].add(y)
  
  
def TSort(g):
    V = list(g.keys())
    for v in list(g.values()):
        V.extend(list(v))
    V = set(V)
    funin = Counter()
    
    for u in V:
        for v in g[u]:
            funin[v] += 1
    
    q = deque()
    for v in V:
        if funin[v] == 0:
            q.append(v)
    L = []
    while q:
        u = q.popleft()
        L.append(u)
        for v in g[u]:
            funin[v] -= 1
            if funin[v] == 0:
                q.append(v)
    return L

  
D = Counter()
ns = TSort(g)
for u in ns:
  for v in g[u]:
    D[v] = max(D[v], D[u] + 1)
print((D.most_common()[0][1]))
# Original solution
import sys
from functools import lru_cache

sys.setrecursionlimit(100000)


@lru_cache(maxsize=None)
def dfs(v):
    lv = links[v]
    return max(dfs(u) for u in lv) + 1 if lv else 0


n, m = list(map(int, input().split()))
sss = set(range(n))
links = [set() for _ in range(n)]
for line in sys.stdin.readlines():
    x, y = list(map(int, line.split()))
    x -= 1
    y -= 1
    sss.discard(y)
    links[x].add(y)

print((max(dfs(v) for v in sss)))


# Optimized solution
import sys
from functools import lru_cache

sys.setrecursionlimit(1000000)


@lru_cache(maxsize=None)
def dfs(v):
    lv = links[v]
    return max(list(map(dfs, lv))) + 1 if lv else 0


n, m = list(map(int, input().split()))
sss = set(range(n))
links = [set() for _ in range(n)]
for line in sys.stdin.readlines():
    x, y = list(map(int, line.split()))
    x -= 1
    y -= 1
    sss.discard(y)
    links[x].add(y)

print((max(list(map(dfs, sss)))))
# Original solution
import sys
from functools import lru_cache

sys.setrecursionlimit(1000000)


@lru_cache(maxsize=None)
def dfs(v):
    lv = links[v]
    return max(list(map(dfs, lv))) + 1 if lv else 0


n, m = list(map(int, input().split()))
sss = set(range(n))
links = [set() for _ in range(n)]
for line in sys.stdin.readlines():
    x, y = list(map(int, line.split()))
    x -= 1
    y -= 1
    sss.discard(y)
    links[x].add(y)

print((max(list(map(dfs, sss)))))


# Optimized solution
import sys

sys.setrecursionlimit(1000000)


def dfs(v):
    if cache[v] > -1:
        return cache[v]
    lv = links[v]
    cache[v] = ret = max(list(map(dfs, lv))) + 1 if lv else 0
    return ret


n, m = list(map(int, input().split()))
sss = set(range(n))
links = [set() for _ in range(n)]
cache = [-1] * n
for line in sys.stdin.readlines():
    x, y = list(map(int, line.split()))
    x -= 1
    y -= 1
    sss.discard(y)
    links[x].add(y)

print((max(list(map(dfs, sss)))))
# Original solution
import sys

sys.setrecursionlimit(1000000)


def dfs(v):
    if cache[v] > -1:
        return cache[v]
    lv = links[v]
    cache[v] = ret = max(list(map(dfs, lv))) + 1 if lv else 0
    return ret


n, m = list(map(int, input().split()))
sss = set(range(n))
links = [set() for _ in range(n)]
cache = [-1] * n
for line in sys.stdin.readlines():
    x, y = list(map(int, line.split()))
    x -= 1
    y -= 1
    sss.discard(y)
    links[x].add(y)

print((max(list(map(dfs, sss)))))


# Optimized solution
import sys

sys.setrecursionlimit(1000000)


def dfs(v):
    if cache[v] > -1:
        return cache[v]
    lv = links[v]
    cache[v] = ret = max(list(map(dfs, lv))) + 1 if lv else 0
    return ret


n, m = list(map(int, input().split()))
links = [set() for _ in range(n)]
cache = [-1] * n
for line in sys.stdin.readlines():
    x, y = list(map(int, line.split()))
    x -= 1
    y -= 1
    links[x].add(y)

print((max(list(map(dfs, list(range(n)))))))
# Original solution
n,m=list(map(int,input().split()))
h={}
st=set([i for i in range(1,n+1)])
kos=set()
for _ in range(m):
    oy,ko=list(map(int,input().split()))
    h.setdefault(oy,[])
    h[oy]+=[ko]
    kos.add(ko)
st=st-kos
dep=0
while 1:
    nst=set()
    for s in st:
        if s not in h:continue
        for ko in h[s]:
            nst.add(ko)
    if len(nst)==0:
        break
    st=nst
    dep+=1
print(dep)

# Optimized solution
import sys

input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)


def get_kyori(i):
    if kos[i] == []:
        kyori[i] = 0
        return 0
    if kyori[i] > -1:
        return kyori[i]
    re = 0
    for ko in kos[i]:
        new = get_kyori(ko) + 1
        if re < new:
            re = new
    kyori[i] = re
    return re


n, m = list(map(int, input().split()))
kos = [[] for _ in range(n + 1)]
kyori = [-1] * (n + 1)
for _ in range(m):
    oya, ko = list(map(int, input().split()))
    kos[oya] += [ko]

for i in range(1, n + 1):
    if kyori[i] == -1:
        kyori[i] = get_kyori(i)

print((max(kyori[1:])))
# Original solution
from collections import deque
n, m = list(map(int, input().split()))
G = [[] for _ in range(n)]
for _ in range(m):
    x, y = [int(x)-1 for x in input().split()]
    G[x].append(y)

counts = [-1] * n

while -1 in counts:
    start = counts.index(-1)
    q = deque([[start, 0]])
    while q:
        i, l = q.pop()
        counts[i] = max(counts[i], l)
        for ni in G[i]:
            q.append([ni, l+1])

print((max(counts)))


# Optimized solution
import sys
sys.setrecursionlimit(500000)
n, m = list(map(int, input().split()))
G = [[] for _ in range(n)]
for _ in range(m):
    x, y = [int(x)-1 for x in input().split()]
    G[x].append(y)

# iを始点としたときの有効パスの最大長さ
dp = [-1] * n
 
def rec(s):
    if dp[s] != -1:
        return dp[s]

    ret = 0
    for ns in G[s]:
        ret = max(ret, rec(ns)+1)
    dp[s] = ret
    return ret

ml = 0    
for i in range(n):
    ml = max(ml, rec(i))
print(ml)
# Original solution
def bell(edges, n):
    dist = [0 for i in range(n)]
 
    changed = True
 
    while changed:
        changed = False
        for edge in edges:
            if dist[edge[1]] < dist[edge[0]] + 1:
                changed = True
                dist[edge[1]] = max(dist[edge[0]] + 1, dist[edge[1]])
                
    return dist
 
 
n,m = list(map(int,input().split()))
edges = []
for _ in range(m):
    a, b= (int(x) for x in input().split())
    edges.append([a-1, b-1])
 
res = bell(edges, n)
print((max(res)))

# Optimized solution
import sys
sys.setrecursionlimit(10**5)
 
n, m = list(map(int, input().split()))
 
edges = [[] for _ in range(n+1)]
for _ in range(m):
    x, y = list(map(int, input().split()))
    edges[x].append(y)
 
dp = [-1 for _ in range(n+1)]
 
def longest_path(u):
    if dp[u] != -1:
        return dp[u]
    d = 0
    for v in edges[u]:
        d = max(d, 1+longest_path(v))
    dp[u] = d
    return d
 
for u in range(1, n+1):
    longest_path(u)
 
print((max(dp)))
# Original solution
# input
N, M = list(map(int, input().split()))
cost = [[float('inf')] * N for i in range(N)]

for i in range(M):
  x, y = list(map(int, input().split()))
  cost[x - 1][y - 1] = -1

for i in range(N):
  for j in range(N):
    for k in range(N):
      cost[i][j] = min(cost[i][j], cost[i][k] + cost[k][j])

ans = 0
for i in range(N):
  for j in range(N):
    if ans > cost[i][j]:
      ans = cost[i][j]

print((ans * -1))

# Optimized solution
# input
N, M = list(map(int, input().split()))
edges = []
for i in range(M):
  edges.append(list(map(int, input().split())))

# DP
cost = [[float(0)] * N for i in range(N)]

for e in edges:
  e[0] -= 1
  e[1] -= 1
  cost[e[0]][e[1]] = 1

for e in edges:
  for i in range(N):
    if cost[i][e[0]] > 0: # i → e.start への経路があるとき
      cost[i][e[1]] = max(cost[i][e[1]], cost[i][e[0]] + 1)
  for j in range(N):
    if cost[e[1]][j] > 0: # e.end → j への経路があるとき
      cost[e[0]][j] = max(cost[e[0]][j], cost[e[1]][j] + 1)

ans = 0
for i in range(N):
  for j in range(N):
    if ans < cost[i][j]:
      ans = cost[i][j]

print(ans)
# Original solution
import sys
N, M = list(map(int, input().split()))

graph = [dict() for _ in range(N)]
for i in range(M):
    x, y = list(map(int, input().split()))
    graph[x - 1][y - 1] = 1

dp = [0 for _ in range(N)]

sys.setrecursionlimit(10 ** 9)


def dfs(num_v):
    if len(graph[num_v]) == 0:
        return
    for to in list(graph[num_v].keys()):
        dp[to] = max(dp[to], dp[num_v] + 1)
        dfs(to)


ans = 0
for i in range(N):
    dfs(i)
    ans = max(ans, max(dp))
print(ans)


# Optimized solution
import sys

sys.setrecursionlimit(10 ** 8)

N, M = list(map(int, input().split()))
graph = [dict() for _ in range(N)]

for i in range(M):
    x, y = list(map(int, input().split()))
    graph[y - 1][x - 1] = 1

dp = [0 for _ in range(N)]


def dfs(u):
    if dp[u] != 0:
        return dp[u]
    max_dis = 0
    for f in list(graph[u].keys()):
        if max_dis < dfs(f) + 1:
            max_dis = dfs(f) + 1

    dp[u] = max_dis
    return dp[u]


for i in range(N):
    dfs(i)
print((max(dp)))
# Original solution
import sys

sys.setrecursionlimit(10 ** 8)

N, M = list(map(int, input().split()))
graph = [dict() for _ in range(N)]

for i in range(M):
    x, y = list(map(int, input().split()))
    graph[y - 1][x - 1] = 1

dp = [0 for _ in range(N)]


def dfs(u):
    if dp[u] != 0:
        return dp[u]
    max_dis = 0
    for f in list(graph[u].keys()):
        if max_dis < dfs(f) + 1:
            max_dis = dfs(f) + 1

    dp[u] = max_dis
    return dp[u]


for i in range(N):
    dfs(i)
print((max(dp)))


# Optimized solution
import sys

sys.setrecursionlimit(10 ** 8)

N, M = list(map(int, input().split()))
graph = [dict() for _ in range(N)]

for i in range(M):
    x, y = list(map(int, input().split()))
    graph[y - 1][x - 1] = 1

dp = [0 for _ in range(N)]


def dfs(u):
    if dp[u] != 0 or len(graph[u]) == 0:
        return dp[u]
    max_dis = 0
    for f in list(graph[u].keys()):
        if max_dis < dfs(f) + 1:
            max_dis = dfs(f) + 1

    dp[u] = max_dis
    return dp[u]


for i in range(N):
    dfs(i)
print((max(dp)))
# Original solution
N, M = list(map(int, input().split()))
childs = [[] for _ in range(N)]
for i in range(M):
    p, c = list(map(int, input().split()))
    childs[p-1].append(c)

stack = list(range(1, N+1))
# dp[n]: nに到達する最長のパス
dp = [0] * N
while stack:
    n = stack.pop()
    for nc in childs[n-1]:
        if dp[nc-1] < dp[n-1] + 1:
            stack.append(nc)
            dp[nc-1] = dp[n-1] + 1

print((max(dp)))


# Optimized solution
import sys
sys.setrecursionlimit(100000)

N, M = list(map(int, input().split()))
childs = [[] for _ in range(N)]
for i in range(M):
    p, c = list(map(int, input().split()))
    childs[p-1].append(c-1)

depth = [-1] * N
def dfs(n):
    if depth[n] != -1:
        return depth[n]
    if childs[n]:
        depth[n] = max((dfs(nc) for nc in childs[n])) + 1
    else:
        depth[n] = 0
    return depth[n]

print((max((dfs(n) for n in range(N)))))
# Original solution
import sys

sys.setrecursionlimit(10**9)

n , m = list(map(int,input().split()))

g = [[] for i in range(n)]

for _ in range(m):
  v1 , v2 = list(map(int,input().split()))
  v1 -=1; v2 -=1
  g[v1].append(v2)
  
# finding longest path for vertice i
def dfs(i):
  temp = 0
  for nv in g[i]:
    temp = max(temp, dfs(nv)+1)
    
  return temp
  
# finding overall longest path  
res = 0  
for i in range(n):
  res = max(res, dfs(i))
  
print(res)

# Optimized solution
import sys

sys.setrecursionlimit(10**9)

n , m = list(map(int,input().split()))

g = [[] for i in range(n)]

dp = [-1] *n
for _ in range(m):
  v1 , v2 = list(map(int,input().split()))
  v1 -=1; v2 -=1
  g[v1].append(v2)
  
# finding longest path for vertice i
def dfs(i):
  if dp[i]!=-1:
    return dp[i]
  temp = 0
  for nv in g[i]:
    temp = max(temp, dfs(nv)+1)
  
  dp[i]=temp
  return temp
  
# finding overall longest path  
res = 0  
for i in range(n):
  res = max(res, dfs(i))
  
print(res)
# Original solution

import sys
sys.setrecursionlimit(10**9)

def dfs(i):
    if distance[i] != -1:
        return distance[i]
    ans = 0
    for node in graph[i]:
        ans = max(ans, dfs(node) + 1)
    return ans

n, m = list(map(int, input().split()))

graph = [[] for i in range(n)]
distance = [-1 for i in range(n)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    graph[a].append(b)

ans = 0
for i in range(n):
    ans = max(ans, dfs(i))

print(ans)

# Optimized solution

import sys
sys.setrecursionlimit(10**9)

def dfs(i):
    if distance[i] != -1:
        return distance[i]
    ans = 0
    for node in graph[i]:
        ans = max(ans, dfs(node) + 1)
    distance[i] = ans
    return ans

n, m = list(map(int, input().split()))

graph = [[] for i in range(n)]
distance = [-1 for i in range(n)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    graph[a].append(b)

ans = 0
for i in range(n):
    ans = max(ans, dfs(i))

print(ans)
# Original solution
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 26 14:22:54 2020

@author: Maruthi Srinivas
"""
import sys
sys.setrecursionlimit(1000000)
def dfs(node,graph,dp):
    temp=0
    if dp[node]!=-1:
        return dp[node]
    for i in graph[node]:
        temp=max(temp,dfs(i,graph,dp)+1)
    dp[node]=temp
    return temp
            
v,e=list(map(int,input().split()))
adj={x:[] for x in range(v+1)}
for i in range(e):
    x,y=list(map(int,input().split()))
    adj[x].append(y)
m=-1
dp=[-1]*(v+1)
for i in range(1,v+1):
    visited=[False]*(v+1)
    x=dfs(i,adj,dp)
    #print(i,x)
    m=max(m,x)
print(m)



# Optimized solution
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 26 14:22:54 2020

@author: Maruthi Srinivas
"""
import sys
sys.setrecursionlimit(1000000)
def dfs(node,graph,dp):
    temp=0
    if dp[node]!=-1:
        return dp[node]
    for i in graph[node]:
        temp=max(temp,dfs(i,graph,dp)+1)
    dp[node]=temp
    return temp
            
v,e=list(map(int,input().split()))
adj={x:[] for x in range(v+1)}
for i in range(e):
    x,y=list(map(int,input().split()))
    adj[x].append(y)
m=-1
dp=[-1]*(v+1)
for i in range(1,v+1):
    x=dfs(i,adj,dp)
    m=max(m,x)
print(m)
# Original solution
from bisect import bisect_left as bl, bisect_right as br, insort
import sys
import heapq
#from math import *
from collections import defaultdict as dd, deque
def data(): return sys.stdin.buffer.readline().strip().decode()
def mdata(): return list(map(int, data().split()))
out=sys.stdout.write
#sys.setrecursionlimit(100000)
INF=int(10e9)


n,m=mdata()
dp=[0]*n
g=[set() for i in range(n)]
par=[i for i in range(n)]
for i in range(m):
    x,y=mdata()
    g[x-1].add(y-1)
for i in range(n):
    if par[i]==i:
        s1=set()
        s1.add(i)
        while s1:
            s2=set()
            for i in s1:
                for j in g[i]:
                    s2.add(j)
                    dp[j]=max(dp[j],dp[i]+1)
            s1=s2.copy()
print((max(dp)))





# Optimized solution
from bisect import bisect_left as bl, bisect_right as br, insort
import sys
import heapq
#from math import *
from collections import defaultdict as dd, deque
def data(): return sys.stdin.buffer.readline().strip().decode()
def mdata(): return list(map(int, data().split()))
out=sys.stdout.write
#sys.setrecursionlimit(100000)
INF=int(10e9)


n,m=mdata()
dp=[0]*n
g=[set() for i in range(n)]
par=[i for i in range(n)]
chl=[0]*n
for i in range(m):
    x,y=mdata()
    g[x-1].add(y-1)
    chl[y-1]=1
vis=[0]*n
for i in range(n):
    if chl[i]==0:
        s1=deque()
        s1.append(i)
        while s1:
            a=s1[-1]
            if vis[a]==1:
                if a!=i:
                    dp[par[a]]=max(dp[par[a]],dp[a]+1)
                s1.pop()
                continue
            vis[a]=1
            for j in g[a]:
                if vis[j]==0:
                    s1.append(j)
                    par[j]=a
                else:
                    dp[a]=max(dp[a],dp[j]+1)
print((max(dp)))
# Original solution
import sys
sys.setrecursionlimit(20000)
def getMax(d,n,c):
    global bs
    if len(d[n])==0:
        bs=max(bs,c)

    for k in d[n]:
        getMax(d,k,c+1)

n,m=list(map(int,input().split()))
d={}
for j in range(1,n+1):
    d[j]=[]
for i in range(m):
    a,b=list(map(int,input().split()))
    d[a].append(b)
bs=-1
for i in range(1,n+1):
    c=0
    getMax(d,i,c)
print(bs)


# Optimized solution
import sys

sys.setrecursionlimit(20000)


def getMax(d, n):
    if len(d[n]) == 0:
        return 0
    if not dp[n] == -1:
      
        return dp[n]
    for k in d[n]:
        dp[n] = max(dp[n], 1 + getMax(d, k))
    return dp[n]


n, m = list(map(int, input().split()))
d = {}
dp = [-1 for _ in range(n + 1)]
for j in range(1, n + 1):
    d[j] = []
for i in range(m):
    a, b = list(map(int, input().split()))
    d[a].append(b)
bs = -1
for i in range(1, n + 1):
    bs = max(bs, getMax(d,i))
print(bs)
# Original solution
import sys
sys.setrecursionlimit(10**9)

def f(x):#dpは
    if dp[x]!=-1:
        return dp[x]#すでに値が決まっていたらそれをかえす
    ans=0
    for e in d[x]:#すべての枝について
        ans=max(ans,1+f(e))
    dp[x]=ans
    return ans

n,m = list(map(int, input().split()))

d={}
dp=[-1]
for i in range(1,n+1):
    d[i]=[]#dは初期値を[]
    dp.append(-1)#dpは初期値-1

for _ in range(m):
    a,b = list(map(int, input().split()))
    d[a].append(b)#有向グラフをdictで
    
ans=0
for i in range(1,n+1):
    ans=max(ans,f(i))
print(ans)

# Optimized solution
import sys
sys.setrecursionlimit(10**9)

def dfs(x): #グラフでの再帰DFS
    if dp[x] != -1:
        return dp[x] #すでに値が決まっていたらそれをかえす
    ans = 0
    for e in graph[x]: #すべての枝について
        ans = max(ans,1 + dfs(e))
    dp[x] = ans
    return ans # 最も長い距離を返す　

n,m = list(map(int, input().split()))

graph = [[] for i in range(n+1)]
dp = [-1]
for i in range(1,n+1):
    dp.append(-1) # dpは初期値-1

for _ in range(m): # グラフの作成
    a,b = list(map(int, input().split()))
    graph[a].append(b)
    #graph[b].append(a) #無向グラフの時
    
ans=0

for i in range(1,n+1):
    ans=max(ans,dfs(i))
print(ans)
# Original solution
import sys
from collections import deque
sys.setrecursionlimit(10 ** 7)
f_inf = float('inf')
mod = 10 ** 9 + 7


def resolve():
    n, m = list(map(int, input().split()))

    # 各頂点の次数
    deg = [0 for _ in range(n)]
    # グラフ
    edge = [[] for _ in range(n)]
    for _ in range(m):
        a, b = list(map(int, input().split()))
        edge[a - 1].append(b - 1)
        deg[b - 1] += 1

    que = deque([])
    for i in range(n):
        if deg[i] == 0:
            que.append(i)

    dp = [0 for _ in range(n)]
    while que:
        v = que.popleft()
        for nv in edge[v]:
            deg[nv] -= 1
            if deg[nv] == 0:
                que.append(nv)
                dp[nv] = max(dp[nv], dp[v] + 1)

    res = 0
    for j in range(n):
        res = max(res, dp[j])
    print(res)


if __name__ == '__main__':
    resolve()


# Optimized solution
import sys
from collections import deque

sys.setrecursionlimit(10 ** 7)
f_inf = float('inf')
mod = 10 ** 9 + 7


def resolve():
    n, m = list(map(int, input().split()))

    # 各頂点の次数
    deg = [0 for _ in range(n)]
    # グラフ
    edge = [[] for _ in range(n)]
    for _ in range(m):
        a, b = list(map(int, input().split()))
        edge[a - 1].append(b - 1)
        deg[b - 1] += 1

    # 入力辺を持たないノードの集合
    que = deque([])
    for i in range(n):
        if deg[i] == 0:
            que.append(i)

    # トポロジカルソートを行いながら、入力辺を持たないノードからの最長経路を求める
    dp = [0 for _ in range(n)]
    while que:
        v = que.popleft()
        for nv in edge[v]:
            # 入力辺を一つ消す
            deg[nv] -= 1
            if deg[nv] == 0:
                que.append(nv)
                dp[nv] = max(dp[nv], dp[v] + 1)

    print((max(dp)))


if __name__ == '__main__':
    resolve()
# Original solution
n, m = list(map(int, input().split()))
xy = [list(map(int, input().split())) for _ in range(m)]

dp = [[0,0] for _ in range(n+1)]

check = True
while(check):
    check = False
    for i in range(m):
        x, y  =xy[i]
        if(dp[x][1] < dp[y][1]+1):
            dp[x][1] =  dp[y][1]+1
            check = True
        if(dp[y][0] < dp[x][0]+1):
            dp[y][0] = dp[x][0]+1
            check = True

ans = 0
for i in range(n+1):
     ans = max(ans, dp[i][0])

print(ans)

# Optimized solution
from sys import setrecursionlimit
setrecursionlimit(10 ** 7)

n, m = list(map(int, input().split()))

xy_dict = {}
for i in range(1,n+1):
    xy_dict[i] = []

for i in range(m):
    x,y = list(map(int, input().split()))
    xy_dict[x].append(y)

dp = [-1]*(n+1)
dp[0] = 0

def get_longest(x):
    global dp

    if( dp[x] >= 0):
        return dp[x]
    else:
        y_list = xy_dict[x]
        temp_max = 0
        for y in y_list:
            temp_max = max(temp_max, get_longest(y)+1)

        dp[x] = temp_max
        return temp_max

ans = 0
for i in range(1,n+1):
    ans = max(ans, get_longest(i))

print(ans)