CodeEff/ECCO huggingface dataset:
# Original solution
import sys
sys.setrecursionlimit(10 ** 5 + 5)
input = sys.stdin.readline
'''
allinputs = iter(input().splitlines())
input = lambda : next(allinputs)
#'''
N, M = list(map(int, input().split()))
x, y = [0] * M, [0] * M
from_x = [[] for _ in range(N)]
memo = [-1] * N
ans = 0

def length(i):
	if memo[i] >= 0:
		return memo[i]
	else:
		if len(from_x[i]) == 0:
			memo[i] = 0
			return memo[i]
		else:
			ret = 0
			
			for j in from_x[i]:
				tmp = length(j) + 1
				if tmp > ret:
					ret = tmp
					
			memo[i] = ret
			return ret

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

for i in range(N):
	tmp = length(i)
	if tmp > ans:
		ans = tmp

print(ans)


# Optimized solution
import sys
input = sys.stdin.readline
'''
allinputs = iter(input().splitlines())
input = lambda : next(allinputs)
#'''
N, M = list(map(int, input().split()))
to_y = [[] for _ in range(N)]
deg = [0] * N
stack = []
dp = [0] * N

for _ in range(M):
	x, y = list(map(int, input().split()))
	to_y[x - 1].append(y - 1)
	deg[y - 1] += 1
	
for i in range(N):
	if deg[i] == 0:
		stack.append(i)
		
while stack:
	x = stack.pop(-1)
	for y in to_y[x]:
		dp[y] = max(dp[y], dp[x] + 1)
		deg[y] -= 1
		if deg[y] == 0:
			stack.append(y)
			
print((max(dp)))
# Original solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
n, m = list(map(int, input().split()))
edges = [[] for _ in range(n)]
for _ in range(m):
    x, y = list([int(x)-1 for x in input().split()])
    edges[x].append(y)


def memoize(f):
    memo = dict()

    def memoized(*args):
        if args in list(memo.keys()):
            return memo[args]
        else:
            memo[args] = f(*args)
            return memo[args]
    return memoized

@memoize
def longest_path(v):
    retval = 0
    for v2 in edges[v]:
        retval = max(retval, longest_path(v2)+1)
    return retval


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

# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
n, m = list(map(int, input().split()))
edges = [[] for _ in range(n)]
for _ in range(m):
    x, y = list([int(x)-1 for x in input().split()])
    edges[x].append(y)

dist = [-1]*n


def longest_path(v):
    if dist[v] != -1:
        return dist[v]
    retval = 0
    for v2 in edges[v]:
        retval = max(retval, longest_path(v2)+1)
    dist[v] = retval
    return dist[v]


ans = 0
for i in range(n):
    ans = max(ans, longest_path(i))
print(ans)
# Original solution
from collections import deque, defaultdict
import sys
input = sys.stdin.readline
n, m = list(map(int, input().split()))
edges = [[]for _ in range(n)]
dd = defaultdict(int)
for _ in range(m):
    x, y = list([int(x)-1 for x in input().split()])
    edges[x].append(y)
    dd[y] += 1

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

toposorted = []
while queue:
    v = queue.popleft()
    toposorted.append(v)
    for v2 in edges[v]:
        if dd[v2] <= 0:
            continue
        dd[v2] -= 1
        if dd[v2] == 0:
            queue.append(v2)

dist = [0]*n
for i in range(n):
    v = toposorted[i]
    for v2 in edges[v]:
        if dist[v2] <= dist[v]-1:
            continue
        dist[v2] = dist[v]-1
print((-min(dist)))


# Optimized solution
from collections import deque
import sys
input = sys.stdin.readline
n, m = list(map(int, input().split()))
edges = [[]for _ in range(n)]
dinp = [0]*n
for _ in range(m):
    x, y = list([int(x)-1 for x in input().split()])
    edges[x].append(y)
    dinp[y] += 1

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

toposorted = []
while queue:
    v = queue.popleft()
    toposorted.append(v)
    for v2 in edges[v]:
        dinp[v2] -= 1
        if dinp[v2] == 0:
            queue.append(v2)

dist = [0]*n
for i in range(n):
    v = toposorted[i]
    for v2 in edges[v]:
        if dist[v2] <= dist[v]-1:
            continue
        dist[v2] = dist[v]-1
print((-min(dist)))
# Original solution
from collections import deque


n, m = list(map(int, input().split()))
info = [list(map(int, input().split())) for i in range(m)]

tree = [[] for i in range(n)]
for i in range(m):
    a, b = info[i]
    a -= 1
    b -= 1
    tree[a].append(b)

set_ = set([])
for i in range(n):
    for j in tree[i]:
        set_.add(j)

start = set([])
for i in range(n):
    if i not in set_:
        start.add(i)

q = deque([])
for i in start:
    q.append(i)
dp = [0]*n
while q:
    pos = q.popleft()
    for next_pos in tree[pos]:
        if dp[pos] + 1 > dp[next_pos]:
            dp[next_pos] = dp[pos] + 1
            q.append(next_pos)
print((max(dp)))

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


n, m = list(map(int, input().split()))
info = [list(map(int, input().split())) for i in range(m)]

tree = [[] for i in range(n)]
for i in range(m):
    a, b = info[i]
    a -= 1
    b -= 1
    tree[a].append(b)

set_ = set([])
for i in range(n):
    for j in tree[i]:
        set_.add(j)

start = set([])
for i in range(n):
    if i not in set_:
        start.add(i)

memo = {}
dp = [0]*n

def solve(pos):
    if pos in memo:
        return memo[pos]
    if len(tree[pos]) == 0:
        memo[pos] = 0
        return memo[pos]

    tmp = 0
    for next_pos in tree[pos]:
        tmp = max(solve(next_pos) + 1, tmp)
    memo[pos] = tmp
    return memo[pos]

for i in range(n):
    solve(i)
ans = 0
for i in memo:
    ans = max(ans, memo[i])
print(ans)
# Original solution
def dfs(num,count,ans):
    #print(num,count)
    ans=max(ans,count)
    for index,item in enumerate(l[num-1]):
        if item==1:
            dp[index+1]=max(dp[index+1],count)
            ans=dfs(index+1,count+1,ans)
    return ans
    
N,M=list(map(int,input().split()))

l=[[0]*N for _ in range(N)]

start=[i+1 for i in range(N)]

for _ in range(M):
    x,y=list(map(int,input().split()))
    l[x-1][y-1]=1
    try:
        start.remove(y)
    except:
        pass
#print(l)

dp=[0]*(N+1)
ans=0
for i in start:
    ans=max(dfs(i,0,0),ans)

#print(dp)
print(ans)
    

# Optimized solution
# coding: utf-8
# Your code here!
from sys import setrecursionlimit
setrecursionlimit(10 ** 7)

N,M=list(map(int,input().split()))

linked=[[] for i in range(N)]

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



def saiki(num):
    if visited[num]==1:
        return dp[num]
    
    visited[num]=1
    value=0
    if linked[num]:
        for item in linked[num]:
            value=max(value,saiki(item)+1)
    dp[num]=value
    return value

dp=[0]*N
visited=[0]*N
ans=0
for i in range(N):
    ans=max(ans,saiki(i))

print(ans)
# Original solution
import sys
def input(): return sys.stdin.readline().rstrip()
from functools import lru_cache
sys.setrecursionlimit(10**6)
@lru_cache(maxsize=None)
def rec(v):
    res=0
    for nv in graph[v]:
        res=max(res,rec(nv)+1)
    return res
def main():
    n,m=list(map(int,input().split()))
    XY=[tuple(map(int,input().split())) for i in range(m)]
    global dp,graph
    graph=[[]for _ in range(n)]
    for x,y in XY:
        graph[x-1].append(y-1)
    dp=[-1]*n #頂点i(0-)を始点としたときの有効パスの長さの最大値
    ans=0
    for v in range(n):
        ans=max(ans,rec(v))
    print(ans)

if __name__=='__main__':
    main()

# Optimized solution
import sys
def input(): return sys.stdin.readline().rstrip()
from functools import lru_cache
sys.setrecursionlimit(10**6)
@lru_cache(maxsize=None)
def rec(v):
    res=0
    for nv in graph[v]:
        res=max(res,rec(nv)+1)
    return res
def main():
    n,m=list(map(int,input().split()))
    XY=[tuple(map(int,input().split())) for i in range(m)]
    global graph
    graph=[[]for _ in range(n)]
    for x,y in XY:
        graph[x-1].append(y-1)
    ans=0
    for v in range(n):
        ans=max(ans,rec(v))
    print(ans)

if __name__=='__main__':
    main()
# Original solution
import sys
def input(): return sys.stdin.readline().rstrip()
from functools import lru_cache
sys.setrecursionlimit(10**6)
@lru_cache(maxsize=None)
def rec(v):
    res=0
    for nv in graph[v]:
        res=max(res,rec(nv)+1)
    return res
def main():
    n,m=list(map(int,input().split()))
    XY=[tuple(map(int,input().split())) for i in range(m)]
    global graph
    graph=[[]for _ in range(n)]
    for x,y in XY:
        graph[x-1].append(y-1)
    ans=0
    for v in range(n):
        ans=max(ans,rec(v))
    print(ans)

if __name__=='__main__':
    main()

# Optimized solution
import sys
def input(): return sys.stdin.readline().rstrip()
sys.setrecursionlimit(10**6)
def rec(v):
    if dp[v]!=-1:return dp[v]
    res=0
    for nv in graph[v]:
        res=max(res,rec(nv)+1)
    dp[v]=res
    return res
def main():
    n,m=list(map(int,input().split()))
    XY=[tuple(map(int,input().split())) for i in range(m)]
    global dp,graph
    graph=[[]for _ in range(n)]
    for x,y in XY:
        graph[x-1].append(y-1)
    dp=[-1]*n #頂点i(0-)を始点としたときの有効パスの長さの最大値
    ans=0
    for v in range(n):
        ans=max(ans,rec(v))
    print(ans)

if __name__=='__main__':
    main()
# Original solution
from collections import deque

def main():
    n, adj = getInputs()

    # maxDistance[start]
    maxDistance = [0] * n
    calculated = set()

    for v in getVertexSequence(n, adj):
        # distance[dest] (starting at v)
        distance = [0] * n

        toVisit = deque([v])

        while len(toVisit) > 0:
            curr = toVisit.popleft()

            for dest in adj[curr]:
                if dest in calculated:
                    distance[dest] = max(
                        distance[dest],
                        distance[curr] + maxDistance[dest] + 1
                    )
                else:
                    if distance[curr] + 1 > distance[dest]:
                        distance[dest] = distance[curr] + 1

                    toVisit.append(dest)

        maxDistance[v] = max(distance)
        calculated.add(v)

    print((max(maxDistance)))

def getInputs():
    n, m = [int(x) for x in input().split()]

    adj = []
    for i in range(n):
        adj.append([])

    for i in range(m):
        a, b = [int(x) for x in input().split()]
        adj[a - 1].append(b - 1)

    return n, adj

def getVertexSequence(n, adj):
    pairs = []
    for i in range(n):
        pairs.append((i, adj[i]))

    pairs.sort(key=(lambda x: len(x[1])))

    sequence = []
    for i in range(n):
        sequence.append(pairs[i][0])

    return sequence

main()


# Optimized solution
import sys
sys.setrecursionlimit(1000000)
def main():
    n, m = [int(x) for x in input().split()]
    global dp
    dp = [-1]*n
    grafo = [[] for _ in range(n)]

    for _ in range(m):
        x, y = [int(x) for x in input().split()]
        x -= 1
        y -= 1

        grafo[x].append(y)

    resp = 0
    for u in range(n):
        resp = max(dfs(u, grafo), resp)

    print(resp)
        

def dfs(u, grafo):
    global dp

    if len(grafo[u]) == 0:
        dp[u] = 0
        return dp[u]

    if dp[u] != -1:
        return dp[u]


    for v in grafo[u]:
        dp[u] = max(dfs(v, grafo) + 1, dp[u])

    return dp[u]
        
main()
# Original solution
import sys
input=sys.stdin.readline

def longest_path(s):
    global dp
    if adj[s]:
        dp[s-1]=max((longest_path(t)+1)for t in adj[s])
    else:
        dp[s-1]=0
    return dp[s-1]

N,M=list(map(int,input().split()))
edge=[]
for _ in range(M):
    edge.append(list(map(int,input().split())))

adj={}
for n in range(1,N+1):
    l=[]
    for m in range(M):
        if edge[m][0]==n:
            l.append(edge[m][1])
    adj[n]=l

dp=[0]*N
for i in range(1,N+1):
    if dp[i-1]==0:
        longest_path(i)

print((max(dp)))

# Optimized solution
import sys
input=sys.stdin.readline
sys.setrecursionlimit(10**6)

def longest_path(s):
    global dp
    if dp[s-1]<1:
        if edge[s]:
            dp[s-1]=max((longest_path(t)+1)for t in edge[s])
        else:
            dp[s-1]=0
    return dp[s-1]

N,M=list(map(int,input().split()))
edge={}
for i in range(1,N+1):
    edge.setdefault(i,[])
for _ in range(M):
    x,y=list(map(int,input().split()))
    edge[x].append(y)
dp=[0]*N
for i in range(1,N+1):
    if dp[i-1]==0:
        longest_path(i)

print((max(dp)))
# Original solution
import sys
sys.setrecursionlimit(10**7)
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x) - 1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def II(): return int(sys.stdin.readline())
def SI(): return sys.stdin.readline().strip()
INF = 10 ** 18
MOD = 10 ** 9 + 7

from functools import lru_cache


def main():
    N, M = LI()
    es = [[x for x in LI()] for _ in range(M)]

    from collections import defaultdict
    outs = defaultdict(list)  # ノードが int なら、[[] for _ in range(n+1)] でもよさそう。
    # ins = defaultdict(int)    # ノードが int なら、 [0 for _ in range(n+1)] でもよさそう。
    for from_v, to_v in es:
        outs[from_v].append(to_v)
        # ins[to_v] += 1

    @lru_cache()
    def max_len(v):
        if not outs[v]:
            return 0
        else:
            return max([max_len(x)+1 for x in outs[v]])

    print((max([max_len(x) for x in range(1,N+1)])))

main()

# Optimized solution
import sys
sys.setrecursionlimit(10**7)
def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x) - 1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def II(): return int(sys.stdin.readline())
def SI(): return sys.stdin.readline().strip()
INF = 10 ** 18
MOD = 10 ** 9 + 7

# from functools import lru_cache


def main():
    N, M = LI()
    es = [[x for x in LI()] for _ in range(M)]

    from collections import defaultdict
    outs = defaultdict(list)  # ノードが int なら、[[] for _ in range(n+1)] でもよさそう。
    # ins = defaultdict(int)    # ノードが int なら、 [0 for _ in range(n+1)] でもよさそう。
    for from_v, to_v in es:
        outs[from_v].append(to_v)
        # ins[to_v] += 1

    # @lru_cache()
    memo = [None for _ in range(N+1)]
    def max_len(v):
        if memo[v] is not None:
            return memo[v]

        if not outs[v]:
            memo[v] = 0
            return 0
        else:
            memo[v] = max([max_len(x)+1 for x in outs[v]])
            return memo[v]

    print((max([max_len(x) for x in range(1,N+1)])))


main()
# Original solution


def main():
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10000000)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations, permutations
    #from itertools import accumulate, product
    from bisect import bisect_left,bisect_right
    from math import floor, ceil
    #from operator import itemgetter

    #mod = 1000000007

    N, M = list(map(int, input().split()))
    g = [[] for _ in range(N)] #場合によって変える
    
    for _ in range(M):
        x, y = list(map(int, input().split()))
        g[x-1].append(y-1)
    dp = [0]*N
    
    def func(i):
        for j in g[i]:
            dp[j] = max(dp[j], dp[i]+1)
            func(j)

    for i in range(N):
        if dp[i]==0:
            func(i)
    print((max(dp)))


if __name__ == '__main__':
    main()

# Optimized solution
#トポロジカルソートなるもの
#再帰で書いてるところをwhileで書いてる
#要は無駄な探索(再帰呼び出し)を無くしてる
#まぁ思いつかない

def main():
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10000000)
    from collections import Counter, deque
    #from collections import defaultdict
    from itertools import combinations, permutations
    #from itertools import accumulate, product
    from bisect import bisect_left,bisect_right
    from math import floor, ceil
    #from operator import itemgetter

    #mod = 1000000007

    n,m = list(map(int,input().split()))
    edge = [[] for i in range(n)]
    #st:入る辺が無い頂点
    st = []
    #to[i]:頂点iに入る辺数
    to = [0]*n
    for i in range(m):
        x,y = list(map(int, input().split()))
        edge[x-1].append(y-1)
        to[y-1] += 1
    for i in range(n):
        if to[i] == 0:
            st.append(i)

    #dp[i]:頂点iを終点とする最長のパスの長さ
    dp = [0]*n
    while st:
        go = st.pop()
        for e in edge[go]:
            to[e] -= 1
            if to[e] == 0:
                st.append(e)
            dp[e] = max(dp[e],dp[go]+1)
    print((max(dp)))


if __name__ == '__main__':
    main()
# Original solution
# coding: utf-8
# Your code here!
from functools import lru_cache
import sys
sys.setrecursionlimit(10**6)

n,m = [int(i) for i in input().split()]

#ko = [[] for _ in range(n)]
oya = [[] for _ in range(n)]
for _ in range(m):
    x,y = [int(i)-1 for i in input().split()]
#    ko[x].append(y)
    oya[y].append(x)

#memo = [-1]*n

@lru_cache(maxsize=None)
def longest(v): #nを終点とするlongest
#    if memo[v] >= 0:
#        return memo[v]
#    else:
    c=0
    for j in oya[v]:
        c = max(c,longest(j)+1)
#    memo[v] = c
    return c

memo = [longest(i) for i in range(n)]

print((max(memo)))    
#print(memo)


# Optimized solution
# coding: utf-8
# Your code here!
import sys
sys.setrecursionlimit(10**6)

n,m = [int(i) for i in input().split()]

#ko = [[] for _ in range(n)]
oya = [[] for _ in range(n)]
for _ in range(m):
    x,y = [int(i)-1 for i in input().split()]
#    ko[x].append(y)
    oya[y].append(x)

memo = [-1]*n

def longest(v): #nを終点とするlongest
    if memo[v] >= 0:
        return memo[v]
    else:
        c=0
        for j in oya[v]:
            c = max(c,longest(j)+1)
        memo[v] = c
        return c

for i in range(n):
    longest(i)

print((max(memo)))    
#print(memo)
# Original solution
import collections

N,M = list(map(int,input().split()))
L = [[False for j in range(N)] for i in range(N)]

for i in range(M) :
    a,b = list(map(int,input().split()))
    a -= 1
    b -= 1
    L[a][b] = True

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

for i in range(N) :
    q = collections.deque()
    q.append(i)
    dist = [0 for i in range(N)]
    while q :
        now = q.pop()
        for j in range(N) :
            if not L[now][j] :
                continue
            dist[j] = max(dist[j], dist[now]+1)
            if j < i :
                dp[i] = max(dp[i], dist[j] + dp[j])
            else :
                q.append(j)
    dp[i] = max(dp[i], max(dist))

ans = max(dp)
print(ans)

    

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

L_minus = [[] for i in range(N)]
L_plus = [0 for i in range(N)]

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

for i in range(M) :
    x,y = L[i]
    x -= 1
    y -= 1
    L_plus[y] += 1
    L_minus[x].append(y)

A = []

for i in range(N) :
    if L_plus[i] == 0 :
        A.append(i)

while A :
    x = A.pop()
    
    for y in L_minus[x] :
        L_plus[y] -= 1
        if L_plus[y] == 0 :
            A.append(y)
        dp[y] = max(dp[y], dp[x]+1)

ans = max(dp)

print(ans)
# Original solution
from collections import deque
n,m = list(map(int,input().split()))
g = [[] for i in range(n)]
h = [[] for i in range(n)]
for i in range(m):
  x,y = list(map(int,input().split()))
  x-=1;y-=1
  g[x].append(y)
  h[y].append(x)
hukasa = [0]*n
MIN = float("inf")
for i in range(n):
  MIN = min(MIN,len(h[i]))
def dfs(x,y):
  for k in g[x]:
    if hukasa[k] < y+1:
      que.append([k,y+1])
for i in range(n):
  if MIN == len(h[i]):
    que = deque([])
    que.append([i,0])
    while que:
      x,y = que.popleft()
      hukasa[x] = y
      dfs(x,y)
for i in range(n):
  hukasa[i] = [hukasa[i],i]
hukasa.sort()
dp = [0] * n
for l,i in hukasa:
  for j in g[i]:
    if dp[j] < dp[i]+1:
      dp[j] = dp[i]+1
print((max(dp)))

# Optimized solution
import heapq
from collections import deque
n,m = list(map(int,input().split()))
g = [[] for i in range(n)]
h = [[] for i in range(n)]
for i in range(m):
  x,y = list(map(int,input().split()))
  x-=1;y-=1
  g[x].append(y)
  h[y].append(x)
hukasa = [0]*n
MIN = float("inf")
for i in range(n):
  MIN = min(MIN,len(h[i]))
def dfs(x,y):
  for k in g[x]:
    if hukasa[k] < y+1:
      heapq.heappush(que,[-(y+1),k])
for i in range(n):
  if MIN == len(h[i]):
    que = [[0,i]]
    heapq.heapify(que)
    while que:
      y,x = heapq.heappop(que)
      if hukasa[x] < -y:
        hukasa[x] = -y
      dfs(x,-y)
print((max(hukasa)))
# Original solution
import heapq
from collections import deque
n,m = list(map(int,input().split()))
g = [[] for i in range(n)]
h = [[] for i in range(n)]
for i in range(m):
  x,y = list(map(int,input().split()))
  x-=1;y-=1
  g[x].append(y)
  h[y].append(x)
hukasa = [0]*n
MIN = float("inf")
for i in range(n):
  MIN = min(MIN,len(h[i]))
def dfs(x,y):
  for k in g[x]:
    if hukasa[k] < y+1:
      heapq.heappush(que,[-(y+1),k])
for i in range(n):
  if MIN == len(h[i]):
    que = [[0,i]]
    heapq.heapify(que)
    while que:
      y,x = heapq.heappop(que)
      if hukasa[x] < -y:
        hukasa[x] = -y
      dfs(x,-y)
print((max(hukasa)))

# Optimized solution
from collections import deque
n,m = list(map(int,input().split()))
g = [[] for i in range(n)]
h = [[] for i in range(n)]
for i in range(m):
  x,y = list(map(int,input().split()))
  x-=1;y-=1
  g[x].append(y)
  h[y].append(x)
topo = []
hukasa = [0] * n
hairu = [0]*n
que = deque([])
for i in range(n):
  hairu[i] = len(h[i])
  if hairu[i] == 0:
    topo.append(i)
    que.append(i)
def dfs(x):
  for i in g[x]:
    hairu[i]-=1
    if hairu[i] == 0:
      topo.append(i)
      que.append(i)
while que:
  x = que.popleft()
  dfs(x)
def dfs2(x):
  for i in g[x]:
    hukasa[i] = max(hukasa[i],hukasa[x]+1)
for i in topo:
  dfs2(i)
print((max(hukasa)))
# Original solution
import sys
from collections import deque

stdin = sys.stdin


def ni(): return int(ns())


def na(): return list(map(int, stdin.readline().split()))


def naa(N): return [na() for _ in range(N)]


def ns(): return stdin.readline().rstrip()  # ignore trailing spaces


N, M = na()
node_dic = {}
no_in = [1] * N

for _ in range(M):
    x, y = na()
    if x-1 in node_dic:
        node_dic[x-1].append(y-1)
    else:
        node_dic[x-1] = [y-1]
    no_in[y-1] = 0


# print(node_dic, no_in)


ans_array = [0] * N

edge = deque([])

for i, x in enumerate(no_in):
    if x == 1:
        deque.append(edge, i)

while(len(edge)):
    e = deque.popleft(edge)
    if e in node_dic:
        for x in node_dic[e]:
            deque.append(edge, x)
            ans_array[x] = max(ans_array[x], ans_array[e] + 1)
    # print(ans_array)
print((max(ans_array)))

# Optimized solution
import sys
from collections import deque
sys.setrecursionlimit(10**8)
stdin = sys.stdin


def ni(): return int(ns())


def na(): return list(map(int, stdin.readline().split()))


def naa(N): return [na() for _ in range(N)]


def ns(): return stdin.readline().rstrip()  # ignore trailing spaces


def cal(e):
    if ans_array[e] != -1:
        return ans_array[e]
    ans = 0
    if e in node_dic:
        for x in node_dic[e]:
            ans = max(ans, cal(x) + 1)
    ans_array[e] = ans
    return ans


N, M = na()
node_dic = {}
no_in = [1] * N

for _ in range(M):
    x, y = na()
    if x-1 in node_dic:
        node_dic[x-1].append(y-1)
    else:
        node_dic[x-1] = [y-1]
    no_in[y-1] = 0


# print(node_dic, no_in)


ans_array = [-1] * N

edge = deque([])

for i, x in enumerate(no_in):
    if x == 1:
        cal(i)


print((max(ans_array)))