CodeEff/ECCO huggingface dataset:
# Original solution
def main():
    import sys
    sys.setrecursionlimit(10**7)

    N,M=list(map(int,sys.stdin.readline().split()))
    dic=[[] for _ in range(N)]
    for i in range(M):
        x,y=list(map(int,sys.stdin.readline().split()))
        dic[x-1].append(y-1)


    dp=[0]*(N)
    def dfs(frm):
        if dp[frm]:
            return dp[frm]

        mx=0
        if not dic[frm]:
            return 0

        for val in dic[frm]:
            mx=max(mx,dfs(val)+1)

        dp[frm]=mx
        return mx

    mx=0
    for key in range(N):
        mx=max(mx,dfs(key))

    return mx

print((main()))


# Optimized solution
def main():
    import sys
    sys.setrecursionlimit(10**7)

    N,M=list(map(int,sys.stdin.readline().split()))
    dic=[[] for _ in range(N)]
    for i in range(M):
        x,y=list(map(int,sys.stdin.readline().split()))
        dic[x-1].append(y-1)


    dp=[0]*(N)
    def dfs(frm):
        if dp[frm]:
            return dp[frm]

        mx=0
        if not dic[frm]:
            return 0

        dp[frm]=max(dfs(val)+1 for val in dic[frm])

        return dp[frm]

    mx=0
    return max(dfs(x) for x in range(N))


print((main()))
# Original solution
from collections import deque
n,m = list(map(int,input().split()))
path = [set() for _ in range(n)]
dp = [0]*n
for _ in range(m):
    x,y = list(map(int,input().split()))
    path[x-1].add(y-1)
    dp[y-1] = -1

que = deque()
for i in range(n):
    if dp[i] == 0:
        que.append(i)
ans = 0
while que:
    p = que.popleft()
    for i in path[p]:
        que.append(i)
        dp[i] = max(dp[i], dp[p] + 1)
        ans = max(ans, dp[i])
print(ans)


# Optimized solution
from collections import deque
n,m = list(map(int,input().split()))
path = [set() for _ in range(n)]
to = [0]*n
dp = [0]*n
for _ in range(m):
    x,y = list(map(int,input().split()))
    path[x-1].add(y-1)
    to[y-1] += 1

que = deque()
for i in range(n):
    if to[i] == 0:
        que.append(i)
ans = 0
while que:
    p = que.popleft()
    for i in path[p]:
        to[i] -= 1
        if to[i] == 0:
            que.append(i)
        dp[i] = max(dp[i], dp[p] + 1)
        ans = max(ans, dp[i])
print(ans)
# Original solution
import sys
import collections

# input処理を高速化する
input = sys.stdin.readline

def chmax(a, b):
    """ 最大値を返す関数 """
    if a >= b:
        return a
    else:
        return b

def main():  
    # 入力
    N, M = list(map(int, input().split()))
    # 隣接関係は隣接リストで管理する
    lst_edge = [[] for _ in range(N)]
    # 各頂点の入力辺の本数
    deg = [0] * N  
    for _ in range(M):
        x, y = list(map(int, input().split()))
        # 最初のindexをゼロにする
        lst_edge[x-1].append(y-1)
        deg[y-1] += 1
    
    # 入力辺を持たない頂点をqueueに入れる
    que = collections.deque()
    for v in range(N):
        if deg[v] == 0:
            que.append(v)

    # 各頂点の最初に入力辺を持たなかった点からの距離
    dp = [0] * N  

    while len(que) > 0:
        v = que.popleft()
        lst_nv = lst_edge[v]
        for nv in lst_nv:
            # エッジ(v, nv)をグラフから削除する
            deg[nv] -= 1
            if deg[nv] == 0:
                # エッジがなくなったことで、入力辺がなくなったらqueueに入れる
                que.append(nv)
                # 最初に入力辺を持たなかった点からの距離
                dp[nv] = chmax(dp[nv], dp[v] + 1)
    
    print((max(dp)))


main()

# Optimized solution
import sys
import collections

# input処理を高速化する
input = sys.stdin.readline

def chmax(a, b):
    """ 最大値を返す関数 """
    if a >= b:
        return a
    return b

def main():
    # 入力
    N, M = list(map(int, input().split()))
    # 隣接関係は隣接リストで管理する
    lst_edge = [[] for _ in range(N)]
    # 各頂点の入力辺の本数
    deg = [0] * N
    for _ in range(M):
        x, y = list(map(int, input().split()))
        # 最初のindexをゼロにする
        lst_edge[x-1].append(y-1)
        deg[y-1] += 1

    # 入力辺を持たない頂点をqueueに入れる
    que = collections.deque()
    for v in range(N):
        if deg[v] == 0:
            que.append(v)

    # 各頂点の最初に入力辺を持たなかった点からの距離
    dp = [0] * N

    while que:
        v = que.popleft()
        lst_nv = lst_edge[v]
        for nv in lst_nv:
            # エッジ(v, nv)をグラフから削除する
            deg[nv] -= 1
            if deg[nv] == 0:
                # エッジがなくなったことで、入力辺がなくなったらqueueに入れる
                que.append(nv)
                # 最初に入力辺を持たなかった点からの距離
                dp[nv] = chmax(dp[nv], dp[v] + 1)

    print((max(dp)))

main()
# Original solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10000000)

N,M=list(map(int,input().split()))
xy = [list(map(int, input().split())) for _ in range(M)]
to = [[]*(N+1) for _ in range(N+1)]
for i in range(M):
    x,y=xy[i]
    to[x].append(y)

dp = [0]*(N+1)

def saiki(v):
    for u in to[v]:
        if dp[u] < dp[v]+1:
            dp[u]=dp[v]+1
            saiki(u)

count = [True]*(N+1)
count[0] = False
for i in range(M):
    count[xy[i][1]] = False

for i in range(1,N+1):
    if count[i]:
        saiki(i)
print((max(dp)))


# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10000000)

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

to = [[]*(N+1) for _ in range(N+1)]
for i in range(M):
    x,y=list(map(int,input().split()))
    to[x].append(y)

dp = [-1]*(N+1)

def saiki(v):
    if dp[v]!=-1: return dp[v]
    res = 0
    for u in to[v]:
        res=max(res,saiki(u)+1)
    dp[v]=res
    return res

ans=0
for i in range(1,N+1):
    ans = max(ans,saiki(i))
print((max(dp)))
# Original solution
# DAGの最長経路...トポロジカルソートもどきか？
# 普通にDAGに沿ったdpをすればいいのでは?
# 再帰だと実装楽そうだけどどうしよう
# 問題は終了と最初がわからんこと
# いや最初は全部長さ0をセットすればいいだろ
import sys
sys.setrecursionlimit(1 << 25)
readline = sys.stdin.buffer.readline
read = sys.stdin.readline  # 文字列読み込む時はこっち
ra = range
enu = enumerate


def exit(*argv, **kwarg):
    print(*argv, **kwarg)
    sys.exit()


def mina(*argv, sub=1): return list(map(lambda x: x - sub, argv))
# 受け渡されたすべての要素からsubだけ引く.リストを*をつけて展開しておくこと


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


def read_col(H):
    '''H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合'''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, readline().split())))
    return tuple(map(list, zip(*ret)))


MOD = 10**9 + 7
INF = 2**31  # 2147483648 > 10**9
# default import
from collections import defaultdict, Counter, deque
from operator import itemgetter, xor, add
from itertools import product, permutations, combinations
from bisect import bisect_left, bisect_right  # , insort_left, insort_right
from functools import reduce

N, M = ints()
dag = defaultdict(lambda: [])
indeg = [0] * N
for _ in ra(M):
    x, y = mina(*ints())
    indeg[y] += 1
    dag[x].append(y)

q = deque()
for u, inn in enu(indeg):  # 多点DFS初期化
    if inn == 0:
        q.append(u)

dp = [0] * N
while q:  # トポロジカル順序でdpテーブルを埋めていく
    u = q.popleft()
    # dp[u] = max(dp[u], l)
    for nx in dag[u]:
        dp[nx] = max(dp[nx], dp[u] + 1)
        indeg[nx] -= 1
        if indeg[nx] == 0:
            q.append(nx)
print(max(dp))


# Optimized solution
# DAGの最長経路...トポロジカルソートもどきか？
# 普通にDAGに沿ったdpをすればいいのでは?
# 再帰だと実装楽そうだけどどうしよう
# 問題は終了と最初がわからんこと
# いや最初は全部長さ0をセットすればいいだろ
import sys
sys.setrecursionlimit(1 << 25)
readline = sys.stdin.buffer.readline
read = sys.stdin.readline  # 文字列読み込む時はこっち
ra = range
enu = enumerate


def exit(*argv, **kwarg):
    print(*argv, **kwarg)
    sys.exit()


def mina(*argv, sub=1): return list(map(lambda x: x - sub, argv))
# 受け渡されたすべての要素からsubだけ引く.リストを*をつけて展開しておくこと


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


def read_col(H):
    '''H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) #一列の場合'''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, readline().split())))
    return tuple(map(list, zip(*ret)))


MOD = 10**9 + 7
INF = 2**31  # 2147483648 > 10**9
# default import
from collections import defaultdict, Counter, deque
from operator import itemgetter, xor, add
from itertools import product, permutations, combinations
from bisect import bisect_left, bisect_right  # , insort_left, insort_right
from functools import reduce

N, M = ints()
dag = defaultdict(lambda: [])
indeg = [0] * N
for _ in ra(M):
    x, y = mina(*ints())
    indeg[y] += 1
    dag[x].append(y)

q = deque()
for u, inn in enu(indeg):  # 多点DFS初期化
    if inn == 0:
        q.append((u, 0))

dp = [0] * N
while q:  # トポロジカル順序でdpテーブルを埋めていく
    u, l = q.popleft()
    # dp[u] = max(dp[u], l)
    dp[u] = max(dp[u], l)
    for nx in dag[u]:
        indeg[nx] -= 1
        if indeg[nx] == 0:
            q.append((nx, l + 1))
print(max(dp))
# Original solution
#!/usr/bin/env python3
#EDPC G

import sys
import math
from bisect import bisect_right as br
from bisect import bisect_left as bl
sys.setrecursionlimit(1000000000)
from heapq import heappush, heappop,heappushpop
from collections import defaultdict
from itertools import accumulate
from collections import Counter
from collections import deque
from operator import itemgetter
from itertools import permutations
mod = 10**9 + 7
inf = float('inf')
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))

def dfs(s):
    if dp[s] != -1:
        return dp[s]
    elif len(edge[s]) == 0:
        return 0
    else:
        res = 0
        for v in edge[s]: 
            res = max(res,dfs(v)+1)
        dp[s] = res
        return res
n,m = LI()
dp = [-1]*n
edge = [[] for _ in range(n)]
for _ in range(m):
    x,y = LI()
    x -= 1
    y -= 1
    edge[x].append(y)

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

# Optimized solution
#!/usr/bin/env python3
#EDPC G

import sys
import math
from bisect import bisect_right as br
from bisect import bisect_left as bl
sys.setrecursionlimit(1000000000)
from heapq import heappush, heappop,heappushpop
from collections import defaultdict
from itertools import accumulate
from collections import Counter
from collections import deque
from operator import itemgetter
from itertools import permutations
mod = 10**9 + 7
inf = float('inf')
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))

def dfs(s):
    if dp[s] != -1:
        return dp[s]
    elif len(edge[s]) == 0:
        dp[s] = 0
        return 0
    else:
        res = 0
        for v in edge[s]: 
            res = max(res,dfs(v)+1)
        dp[s] = res
        return res
n,m = LI()
dp = [-1]*n
edge = [[] for _ in range(n)]
for _ in range(m):
    x,y = LI()
    x -= 1
    y -= 1
    edge[x].append(y)

for i in range(n):
    dfs(i)
print((max(dp)))
# Original solution
from collections import defaultdict
import sys

sys.setrecursionlimit(10**6)


def solve(N, M, edges):
    longest = {}

    def get_longest(start):
        if start in longest:
            return longest[start]

        next_edges = edges.get(start)
        if not next_edges:
            ret = 0
        else:
            ret = max(get_longest(v) for v in edges[start]) + 1
        longest[start] = ret
        return ret

    return max(get_longest(v) for v in edges)


def main():
    N, M = list(map(int, input().split()))
    edges = defaultdict(set)
    for i in range(M):
        v1, v2 = list(map(int, input().split()))
        edges[v1].add(v2)

    print((solve(N, M, edges)))


main()


# Optimized solution
#!/usr/bin/env python3
"""
Simple Version
Python TLE https://atcoder.jp/contests/dp/submissions/14906600
PyPy TLE https://atcoder.jp/contests/dp/submissions/14906630
"""
from collections import defaultdict
import sys

sys.setrecursionlimit(10**6)


def solve(N, M, edges):
    longest = [-1] * (N + 1)
    for i in range(N + 1):
        if not edges[i]:
            longest[i] = 0

    def get_longest(start):
        ret = longest[start]
        if ret != -1:
            return ret

        next_edges = edges.get(start)
        if not next_edges:
            ret = 0
        else:
            ret = max(get_longest(v) for v in edges[start]) + 1
        longest[start] = ret
        return ret

    return max(get_longest(v) for v in edges)


def main():
    N, M = list(map(int, input().split()))
    edges = defaultdict(set)
    for i in range(M):
        v1, v2 = list(map(int, input().split()))
        edges[v1].add(v2)

    print((solve(N, M, edges)))


main()
# Original solution
n, m = list(map(int, input().split()))

edges = [[0 for _ in range(n+1)] for _ in range(n+1)]
for _ in range(m):
    x, y = list(map(int, input().split()))
    edges[x][y] = 1

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

def longest_path(u):
    if dp[u] != -1:
        return dp[u]
    d = 0
    for i in range(1, n+1):
        if edges[u][i]:
            d = max(d, 1+longest_path(i))
    dp[u] = d
    return d

for u in range(n+1):
    longest_path(u)

print((max(dp)))


# 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
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5+1)
from functools import lru_cache

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

    @lru_cache(maxsize=10**5+1)
    def dp(v):
        res = 0
        for w in G[v]:
            res = max(res, dp(w)+1)
        return res

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

if __name__ == '__main__':
    main()

# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**5+1)
from functools import lru_cache

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

@lru_cache(maxsize=10**5+1)
def dp(v):
    res = 0
    for w in G[v]:
        res = max(res, dp(w)+1)
    return res

ans = 0
for i in range(N):
    ans = max(ans, dp(i))
print(ans)
# Original solution
from sys import setrecursionlimit; setrecursionlimit(10**9)
N, M = list(map(int, input().split()))
edge = {}
starts = set(i for i in range(1, N+1))
for _ in range(M):
    x, y = list(map(int, input().split()))
    if x not in edge:
        edge[x] = [y]
    else:
        edge[x].append(y)
    starts -= {y}

def rec(d, e, dp):
    dp[e] = max(dp[e], d)
    if e not in edge:
        return 0
    for f in edge[e]:
        rec(d+1, f, dp)
    return max(dp)

depth = []
for s in starts:
    depth.append(rec(0, s, [0]*(N+1)))
print((max(depth)))


# Optimized solution
from sys import setrecursionlimit; setrecursionlimit(10**9)
N, M = list(map(int, input().split()))
edge = {i:[] for i in range(1, N+1)}
starts = set(i for i in range(1, N+1))
for _ in range(M):
    x, y = list(map(int, input().split()))
    edge[x].append(y)
    starts -= {y}

memo = [-1] * (N+1)

def rec(e):
    if memo[e] != -1:
        return memo[e]
    ret = 0
    for f in edge[e]:
        ret = max(ret, rec(f) + 1)
    memo[e] = ret
    return ret

max_d = 0
for s in starts:
    max_d = max(max_d, rec(s))
print(max_d)
# Original solution
from collections import deque
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline


def read():
    N, M = list(map(int, input().strip().split()))
    E_out = [list() for i in range(N)]
    E_in = [list() for i in range(N)]
    for i in range(M):
        x, y = list(map(int, input().strip().split()))
        E_out[x-1].append(y-1)  # x -> E_out[x]
        E_in[y-1].append(x-1)   # E_in[x] -> x
    return N, M, E_in, E_out


def solve(N, M, E_in, E_out):
    dp = [-1 for i in range(N)]
    q = deque()
    for x in range(N):
        if len(E_out[x]) == 0:
            q.append(x)
            dp[x] = 0
    while q:
        x = q.pop()
        for y in E_in[x]:
            q.append(y)
            dp[y] = max(dp[y], dp[x] + 1)
    return max(dp)


if __name__ == '__main__':
    inputs = read()
    print(("%s" % solve(*inputs)))


# Optimized solution
from collections import deque
import sys
sys.setrecursionlimit(100000)
input = sys.stdin.readline


def read():
    N, M = list(map(int, input().strip().split()))
    parents = [list() for i in range(N)]
    n_children = [0 for i in range(N)]
    for i in range(M):
        x, y = list(map(int, input().strip().split()))
        n_children[x-1] += 1  # x -> E_out[x]
        parents[y-1].append(x-1)   # E_in[x] -> x
    return N, M, n_children, parents


def solve(N, M, n_children, parents):
    dp = [0 for i in range(N)]
    q = deque()
    r = deque()
    for x in range(N):
        if n_children[x] == 0:
            q.append(x)
    while q:
        x = q.pop()
        r.append(x)
        for parent in parents[x]:
            n_children[parent] -= 1
            if n_children[parent] == 0:
                q.append(parent)
    
    while r:
        x = r.pop()
        for y in parents[x]:
            dp[x] = max(dp[x], dp[y]+1)
    return max(dp)


if __name__ == '__main__':
    inputs = read()
    print(("%s" % solve(*inputs)))
# Original solution
N, M = (int(i) for i in input().split()) 

outs = [[] for i in range(N)]
ins = [0] * N


for _ in range(M):
    x, y = (int(i) for i in input().split())
    x -= 1
    y -= 1
    outs[x].append(y)
    ins[y] += 1

q = []
for i in range(N):
    if ins[i] == 0:
        q.append(i)

result = []
while q != []:
    qn = q.pop(0)
    result.append(qn)
    for v in outs[qn]:
        ins[v] -= 1
        if ins[v] == 0:
            q.append(v)


last = [0] * N
# last[i] = iが最後だったときに最長のパス
for sq in result:
    tp = last[sq] + 1
    for v in outs[sq]:
        last[v] = max(last[v], tp)

print((max(last)))


     



# Optimized solution
N, M = (int(i) for i in input().split()) 

outs = [[] for i in range(N)]
ins = [0] * N


for _ in range(M):
    x, y = (int(i) for i in input().split())
    x -= 1
    y -= 1
    outs[x].append(y)
    ins[y] += 1

q = []
for i in range(N):
    if ins[i] == 0:
        q.append(i)

result = []
while q != []:
    qn = q.pop()
    result.append(qn)
    for v in outs[qn]:
        ins[v] -= 1
        if ins[v] == 0:
            q.append(v)


last = [0] * N
# last[i] = iが最後だったときに最長のパス
for sq in result:
    for v in outs[sq]:
        last[v] = max(last[v], last[sq] + 1)

print((max(last)))
# Original solution
import sys
sys.setrecursionlimit(10 ** 9)

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

G = [[] for _ in range(N + 1)]

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

lst = [-1] * (N + 1)


def calc(x):
    if lst[x] != -1:
        return lst[x]
    tmp = 0
    for next_ in G[x]:
        tmp = max(tmp, calc(next_))
    
    lst[x] = tmp + 1
    return tmp + 1

for i in range(1, N + 1):
    if lst[i] == -1:
        calc(i)

print((max(lst) - 1))

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

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

G = [[] for _ in range(N + 1)]

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

lst = [-1] * (N + 1)


def calc(x):
    if lst[x] != -1:
        return lst[x]
    tmp = 0
    for next_ in G[x]:
        tmp = max(tmp, calc(next_))
    
    lst[x] = tmp + 1
    return tmp + 1

ans = 0
for i in range(1, N + 1):
    if lst[i] == -1:
        ans = max(ans, calc(i))

print((ans - 1))
# Original solution
import sys
sys.setrecursionlimit(10**5)

N, M = list(map(int, input().split()))
#dp[v]: start from v maxpath
dp = [-1 for _ in range(N)]

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

#solve DAG and topological sort by recursive funciton
def f(v,G=gragh):
    if dp[v] != -1:
        return dp[v]
    ret = 0
    for u in G[v]:
        ret = max(ret, f(u) + 1)
    return ret
for v in range(N):
    dp[v] = f(v)
print((max(dp)))


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

N, M = list(map(int, input().split()))
#dp[v]: start from v maxpath
dp = [-1 for _ in range(N)]

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

#solve DAG and topological sort by memo recursive funciton
def f(v,G=gragh):
    if dp[v] != -1:
        return dp[v]
    ret = 0
    for u in G[v]:
        ret = max(ret, f(u) + 1)
    dp[v] = ret
    return ret
for v in range(N):
    dp[v] = f(v)
print((max(dp)))
# Original solution

""""
5 8
5 3
2 3
2 4
5 2
5 1
1 4
4 3
1 3
"""

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

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

h = [0]*(N+1)

for eg in G:
    h[eg[1]]+=1

que = []

for i in range(1, N+1):
    if h[i] == 0: que.append(i)

dp = [0]*(N+1)

while len(que)>0:
    now = que.pop(0)
    for eg in G:
        if eg[0]==now:
            h[eg[1]]-=1
            if h[eg[1]]==0:
                que.append(eg[1])
                dp[eg[1]] = max(dp[eg[0]] + 1, dp[eg[1]])

print(max(dp))

# Optimized solution

""""
5 8
5 3
2 3
2 4
5 2
5 1
1 4
4 3
1 3
"""

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

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

h = [0]*(N+1)

dest = [[] for _ in range(N+1)]

for eg in G:
    h[eg[1]]+=1
    dest[eg[0]].append(eg[1])

que = []

for i in range(1, N+1):
    if h[i] == 0: que.append(i)

dp = [0]*(N+1)

while len(que)>0:
    now = que.pop(0)
    for edest in dest[now]:
        h[edest]-=1
        if h[edest]==0:
            que.append(edest)
            dp[edest] = max(dp[now] + 1, dp[edest])

print(max(dp))
# Original solution
# Author: S Mahesh Raju
# Username: maheshraju2020
# Date: 01/08/2020

from sys import stdin,stdout
from math import gcd, ceil, sqrt
from collections import Counter
from bisect import bisect_left, bisect_right
ii1 = lambda: int(stdin.readline().strip())
is1 = lambda: stdin.readline().strip()
iia = lambda: list(map(int, stdin.readline().strip().split()))
isa = lambda: stdin.readline().strip().split()
mod = 1000000007

def bfs(node, d):
    queue = [node, None]
    count = 0
    while len(queue):
        cur = queue.pop(0)
        if not cur:
            if len(queue):
                queue.append(None)
            count += 1
        else:
            for neigh in d.get(cur, []):
                queue.append(neigh)
    return count - 1

n, m = iia()
d = {}
indegree = [0] * (n + 1)
for i in range(m):
    a, b = iia()
    d.setdefault(a, []).append(b)
    indegree[b] += 1

res = 0
for i in range(1, n + 1):
    if indegree[i] == 0:
        res = max(res, bfs(i, d))
print(res)
    
    

# Optimized solution
# Author: S Mahesh Raju
# Username: maheshraju2020
# Date: 01/08/2020

from sys import stdin, stdout
import sys
from math import gcd, ceil, sqrt
from collections import Counter
from bisect import bisect_left, bisect_right
ii1 = lambda: int(stdin.readline().strip())
is1 = lambda: stdin.readline().strip()
iia = lambda: list(map(int, stdin.readline().strip().split()))
isa = lambda: stdin.readline().strip().split()
mod = 1000000007
sys.setrecursionlimit(100000)
n, m = iia()
dp = [-1] * (n + 1)
d = {}
for i in range(m):
    a, b = iia()
    d.setdefault(a, []).append(b)

def dfs(cur):
    if dp[cur] != -1:
        return dp[cur]
    t = 0
    for i in d.get(cur, []):
        t = max(1 + dfs(i), t)
    dp[cur] = t
    return dp[cur]

res = 0
for i in range(1, n + 1):
    res = max(res, dfs(i))
print(res)
# Original solution
import sys
sys.setrecursionlimit(10**7)
def f(v):
    if dp[v] != 0:
        return dp[v]
    res = 0
    for i in graph[v]:
        res = max(res,f(i)+1)
    dp[v] = res
    return res
N, M = list(map(int, input().split()))
graph = [[] for _ in range(N)]
for _ in range(M):
    x, y = list(map(int, input().split()))
    graph[x-1].append(y-1)
dp = [0]*N
for i in range(N):
    f(i)
print((max(dp)))

# Optimized solution
import sys
sys.setrecursionlimit(10**7)
N, M = list(map(int, input().split()))
edge = [[] for _ in range(N)]
for _ in range(M):
    x, y = list(map(int, input().split()))
    edge[x-1].append(y-1)
dp = [0]*N
def f(v):
    if dp[v] != 0:
        return dp[v]
    res = 0
    for i in edge[v]:
        res = max(res, f(i)+1)
    dp[v] = res
    return res
for i in range(N):
    f(i)
print((max(dp)))