CodeEff/ECCO huggingface dataset:
# Original solution
import sys
from collections import deque

def main():

    input = sys.stdin.readline

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

    A = [0] * M
    B = [0] * M

    friend_list = [ set() for _ in range(N)]
    friend_list_len = 0

    for i in range(M):
        A[i],B[i] = list(map(int,input().split()))

        for j in range(friend_list_len):
            flag = False
            if A[i] in friend_list[j]:
                friend_list[j].add(B[i])
                flag = True
            if B[i] in friend_list[j]:
                friend_list[j].add(A[i])
                flag = True
            if flag:
                break                
        else:
            friend_list[friend_list_len].add(A[i])
            friend_list[friend_list_len].add(B[i])
            friend_list_len += 1

    ans = 1
    for i in range(friend_list_len):
        ans = max(ans,len(friend_list[i]))

    print(ans)


if __name__ == "__main__":
    main()

# Optimized solution
import sys


def main():

    input = sys.stdin.readline

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

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

    UF = UnionFind(N)

    for i in range(M):
        A,B = AB[i]

        A = A - 1
        B = B - 1

        UF.union(A,B)


    ans = 1
    for i in range(N):
        ans = max(ans,UF.size(i))

    print(ans)

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n
        
    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
    
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        
        if x == y:
            return
        
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        
        self.parents[x] += self.parents[y]
        self.parents[y] = x
    
    def size(self, x):
        return -self.parents[self.find(x)]
        
    def same(self, x, y):
        return self.find(x) == self.find(y)
    
    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]
    
    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())
    
    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}
    
    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

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

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

edge_list = [set() for i in range (N)]


for i in range (M):
    A,B = list(map(int,input().split()))
    edge_list[A-1].add(B-1)
    edge_list[B-1].add(A-1)

for i in range (N):
    d =deque(edge_list[i])
    while d:
        a = d.popleft()
        el = copy.copy(edge_list[a])
        for j in range (len(edge_list[a])):
            aj = el.pop()
            if (aj not in edge_list[i]) and i != aj:
                edge_list[i].add(aj)
                d.append(aj)


edge_list = list(map(len,edge_list))

print((max(edge_list)+1))


# Optimized solution
class UnionFind:
    def __init__ (self,n):
        self.parent = [i for i in range (n)]
        self.height = [0 for _ in range (n)]

    def get_root(self,i):
        if self.parent[i] == i:
            return i
        else:
            self.parent[i] = self.get_root(self.parent[i])
            return self.parent[i]

    def unite(self,i,j):
        root_i = self.get_root(i)
        root_j = self.get_root(j)
        if root_i != root_j:
            if self.height[root_i] < self.height[root_j]:
                self.parent[root_i] = root_j
            else:
                self.parent[root_j] = root_i
                if self.height[root_i] == self.height[root_j]:
                    self.height[root_i] += 1

    def is_in_group(self,i,j):
        if self.get_root(i) == self.get_root(j):
            return True
        else:
            return False

def main():
    N,M = list(map(int, input().split()))
    uf = UnionFind(N)
    for _ in range (M):
        A,B = [int(x)-1 for x in input().split()]
        uf.unite(A,B)

    check = [0]*N
    for i in range(N):
        check[uf.get_root(i)] += 1
    print((max(check)))


main()
# Original solution
N, M = list(map(int, input().split()))
friends = {i: set([]) for i in range(N)}
for i in range(M):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    friends[a].add(b)
    friends[b].add(a)
#print(friends)
from collections import deque

reached = [-1] * N
ans = 1
for i in range(N):
    if reached[i] == -1:
        queue = deque()
        queue.append(i)
        t = 1
        reached[i] = 0
        while len(queue) > 0:
            v = queue.popleft()
            for n in friends.get(v):
                if reached[n] == -1:
                    reached[n] = 0
                    queue.append(n)
                    t += 1
    ans = max(ans, t)
print(ans)


# Optimized solution
N, M = list(map(int, input().split()))
t = [-1] * N

import sys
sys.setrecursionlimit(10 ** 6)
def find(e):
    if t[e] < 0:
        return e
    else:
        t[e] = find(t[e])
        return t[e]


def unite(a, b):
    a_root = find(a)
    b_root = find(b)
    if a_root == b_root:
        return
    t[a_root] += t[b_root]
    t[b_root] = a_root


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


def size(x):
    x = find(x)
    return -t[x]


ans = 0
for i in range(N):
    ans = max(ans, size(i))
print(ans)
# Original solution
from collections import deque
N,M = list(map(int,input().split()))
graph = []
fship = []
for i in range(M):
    x,y = list(map(int,input().split()))
    if x>y:
        x,y = y,x
    if [x-1,y-1] not in fship:
        fship.append([x-1,y-1])
fship.sort(key = lambda x: x[0])
graph = [[] for _ in range(N)]
for i in fship:
    graph[i[0]].append(i[1])

dist = [None]*N
ans = -1

for i in range(N):
    if dist[i]:
        continue
    dist[i] = True
    tmp = 0
    d = deque()
    d.append(i)
    while d:
        v = d.popleft()
        for i in graph[v]:
            if dist[i]:
                continue
            dist[i] = True
            d.append(i)
            tmp += 1
    ans = max(ans,tmp)
print((ans+1))

# Optimized solution
from collections import deque
N,M = list(map(int,input().split()))
graph = [[] for _ in range(N)]
for i in range(M):
    x,y = list(map(int,input().split()))
    x -= 1
    y -= 1
    graph[x].append(y)
    graph[y].append(x)

seen = [None]*N
ans = -1

for i in range(N):
    if seen[i]:
        continue
    seen[i] = True
    tmp = 0
    d = deque()
    d.append(i)
    while d:
        v = d.popleft()
        for i in graph[v]:
            if seen[i]:
                continue
            seen[i] = True
            d.append(i)
            tmp += 1
    ans = max(ans,tmp)
print((ans+1))
# Original solution

#スタック、キューを使う
from collections import deque

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

G = [ set() for row in range(N)]

for i in range(M):
    A,B = list(map(int,input().split()))
    G[A-1].add(B-1)
    G[B-1].add(A-1)

for i in range(N):
    G[i] = list(G[i])

#1グループに所属する最大数
ans = 0

#友達グループの数
count = 0

#各頂点の状態を色で表す WHITE:未訪問 GRAY:訪問中 BLACK:訪問完了
color = ['WHITE' for i in range(N)]

#訪問途中の頂点を退避しておくスタック
S = deque()

#次の要素を取り出す
def next(u):    
    #G[u]に格納されているまだ未訪問のノードを返す
    for i in range(len(G[u])):
        if color[G[u][i]] == 'WHITE':
            return G[u][i]
    return -1

def dfs(u):
    #始点uをスタックに追加
    S.append(u)
    color[u] = 'GRAY'
    global count
    count += 1
    #dequeは空のとき偽を返す
    while S:
        u = S[-1]    #スタックの頂点をuに格納
        v = next(u)
        #uに未訪問の隣接ノードがある
        if v != -1:
            color[v] = 'GRAY'
            count += 1
            S.append(v)
        else:
            S.pop()
            color[u]='BLACK'

#未訪問のuを始点として深さ優先探索
for i in range(N):
    count = 0
    if color[i] == 'WHITE':
        dfs(i)
        if count >= ans:
            ans = count

print(ans)


# Optimized solution
"""
UnionFindにはいろいろな実装があるが, 本問ではparents配列にノード数を保持する実装だと非常に簡単に解ける. 
以下のようにしてノード数を保持する.
自身が子のとき, 親ノード番号を格納する.
自身が根のとき, ノード数を負の数で格納する.
つまり,　負の数のときは自身が根であり, その絶対値がその木のノード数を表す.
初期化時は、すべてのノードを−1で初期化する.
"""

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

#UnionFind木の実装
#-1で初期化し、併合のたびに-1していく
par = [-1] * N  #親
rank = [0] * N #木の深さ

#木の根を求める
def find(x):
    #par[x]が負のとき(自分が代表のとき)、自身を返す
    if par[x] < 0:
        return x
    else:
        return find(par[x])

#xとyの属する集合を併合
def unite(x,y):
    x = find(x)
    y = find(y)
    #もとから同じ集合のときは何もしない
    if (x == y):
        return
    #x側を常に小さくする
    if par[x] > par[y]:
            x, y = y, x
    
    #x側に併合する、その際xの代表にノード数を加算する
    par[x] += par[y]
    par[y] = x
    

#xとyが同じ集合に属するかどうか
def same(x,y):
    return find(x) == find(y)

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


ans = min(par)

print((abs(ans)))
# Original solution
import sys
input = sys.stdin.readline

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

n, m = list(map(int, input().split()))
uf = UnionFind(n)
for _ in range(m):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    uf.unite(a, b)
D = uf.all_group_members()
ans = 0
for i in list(D.values()):
    ans = max(ans, len(i))
print(ans)

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

n, m = list(map(int, input().split()))
G = [set() for _ in range(n)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    a -= 1
    b -= 1
    G[a].add(b)
    G[b].add(a)
ans = 0
seen = [0]*n
def dfs(v):
    res = 0
    stack = [v]
    seen[v] = True
    while stack:
        res += 1
        v = stack.pop()
        for nv in G[v]:
            if seen[nv]:
                continue
            seen[nv] = True
            stack.append(nv)
    return res
for i in range(n):
    if not seen[i]:
        ans = max(ans, dfs(i))
print(ans)
# Original solution
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

def main():
  n, m = list(map(int, input().split()))
  uf = UnionFind(n)

  for i in range(m):
    a, b = list(map(int, input().split()))
    a -= 1; b-= 1;
    uf.union(a, b)
  
  max_len = 0
  for g in list(uf.all_group_members().values()):
    len_g = len(g)
    if len_g > max_len:
      max_len = len_g
      
  print(max_len)
  
main()

# Optimized solution
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

def main():
  n, m = list(map(int, input().split()))
  uf = UnionFind(n)

  for i in range(m):
    a, b = list(map(int, input().split()))
    a -= 1; b-= 1;
    uf.union(a, b)
  
  ans = 0
  for i in range(n):
    ans = max(ans, uf.size(i))
      
  print(ans)
  
main()
# Original solution
import queue
N, M = list(map(int, input().split()))
l = [[] for i in range(N)]
for i in range(M):
        a, b = list(map(int, input().split()))
        l[a - 1].append(b - 1)
        l[b - 1].append(a - 1)
c = [0] * N 
ans = 1
q = queue.Queue()
for j in range(N):
        q.put(l[j])
        u = 0 
        while not q.empty():
                temp = q.get()
                for k in temp:
                        if c[k]:
                                continue
                        c[k] = 1 
                        u += 1
                        q.put(l[k])
        ans = max(ans, u)
print(ans) 

# Optimized solution
N, M = list(map(int, input().split()))
r = [-1] * (N + 1)

def root(x):
        if r[x] < 0:
                return x
        return root(r[x])

for i in range(M):
        x, y = list(map(int, input().split()))
        x = root(x)
        y = root(y)
        if x == y:
                continue
        if r[x] > r[y]:
                x, y = y, x
        r[x] += r[y]
        r[y] = x 

print((-min(r)))
# Original solution
def uf_find(x):
  if x == p[x]:
    return x
  else:
    p[x] = uf_find(p[x])
    return p[x]

def uf_unite(x,y):
  x = uf_find(x)
  y = uf_find(y)
  if x != y:
    if r[y]>r[x]:
      x,y = y,x
    if r[x]==r[y]:
      r[x]+= 1
    p[y] = x
    #print(r)


N, M = list(map(int, input().split()))
p = list(range(N))
r = [0]*N

for i in range(M):
  A, B = [int(j)-1 for j in input().split()]
  uf_unite(A,B)
  #print(p)
  
#for i in range(N):
  #p[i] = uf_find(i)

q = [0]*N
for i in range(N):
  q[i] = p.count(i)
  
print((max(q)))


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

par = list(range(N))
rank = [1]*N
size = [1]*N

def find(x):
  if par[x] == x:
    return x
  else:
    return find(par[x])
  
def unite(x,y):
  x = find(x)
  y = find(y)
  
  if x == y:
    return
  if rank[x]<rank[y]:
    par[x]=y
    size[y]+= size[x]
  else:
    par[y] = x
    size[x] += size[y]
    if rank[x]==rank[y]:
      rank[x]+=1
    
for i in range(M):
  a,b = [int(i)-1 for i in input().split()]
  unite(a,b)
  
print((max(size)))
# Original solution
from collections import deque

n,m=list(map(int,input().split()))
f=[[] for i in range(n+1)]
for i in range(m):
    a,b=list(map(int,input().split()))
    f[a].append(b)
    f[b].append(a)
g=[0]*(n+1)
p=[0]*(n+1)
for i in range(1,n+1):
    if p[i]==0:
        p[i]=i
        data=[i]
        data=deque(data)
        while len(data)>0:
            pos=data.popleft()
            p[pos]=i
            for j in f[pos]:
                if p[j]==0:
                    data.append(j)
            f[pos]=[]
for i in range(n):
    g[p[i+1]]+=1
print((max(g)))



# Optimized solution
from _collections import deque

n,m=list(map(int,input().split()))
f=[[] for i in range(n+1)]
for i in range(m):
    a,b=list(map(int,input().split()))
    f[a].append(b)
    f[b].append(a)
g=[0]*(n+1)
p=[0]*(n+1)
for i in range(1,n+1):
    if p[i]==0:
        p[i]=i
        data=[i]
        data=deque(data)
        while len(data)>0:
            pos=data.popleft()
            p[pos]=i
            for j in f[pos]:
                if p[j]==0:
                    p[j]=i
                    data.append(j)
for i in range(n):
    g[p[i+1]]+=1
print((max(g)))
# Original solution
from collections import deque
 
N, M = list(map(int, input().split()))
g = {i:set() for i in range(N)}
v = [-1 for i in range(N)]
for _ in range(M):
  a, b = list(map(int, input().split()))
  a, b = a-1, b-1
  g[a].add(b)
  g[b].add(a)
  
Q = deque()
ans = 0
for a in g:
  if v[a]==-1:
    v[a] = 1
    ans_tmp = 1
    Q.append(a)
    while len(Q)>0:
      na = Q.popleft()
      for nb in g[na]:
        if v[nb] == -1:
          v[nb] = 1
          ans_tmp += 1
          Q.append(nb)
    ans = max(ans, ans_tmp)
print(ans)

# Optimized solution
N, M = list(map(int, input().split()))
r = [i for i in range(N+1)]
n = [0 for i in range(N+1)]
buf = []

def root(x):
  if x==r[x]:
    return x
  else:
    r[x] = root(r[x])
    return r[x]

def unite(x, y):
  rx = root(x)
  ry = root(y)
  if rx < ry:
    r[ry] = rx
  elif rx > ry:
    r[rx] = ry
    

for _ in range(M):
  a, b = list(map(int, input().split()))
  unite(a, b)

for x in range(1, N+1):
  if r[x] != x and r[r[x]] != r[x]:
    _ = root(x)
  
  
for x in r[1:]:
  n[x] += 1
    
ans = max(n[1:])

print(ans)
# Original solution
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


n, m = list(map(int, input().split()))
friends = []
for i in range(m):
    f = list(map(int, input().split()))
    f.sort()
    if f not in friends:
        friends.append(f)

friend_map = UnionFind(n)

for f in friends:
    friend_map.union(f[0]-1, f[1]-1)

ans = 0
for i in range(n):
    tmp = friend_map.size(i)
    ans = max(ans, tmp)

print(ans)


# Optimized solution
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

    def __str__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())


n, m = list(map(int, input().split()))
friends = []
for i in range(m):
    f = list(map(int, input().split()))
    friends.append(f)

friend_map = UnionFind(n)

for f in friends:
    friend_map.union(f[0]-1, f[1]-1)

ans = 0
for i in range(n):
    tmp = friend_map.size(i)
    ans = max(ans, tmp)

print(ans)
# Original solution
from collections import deque
N,M=[int(s) for s in input().split()] 
hito=[0 for i in range(N)]
edge=[set() for _ in range(N)]
for i in range(M):
  a,b=[int(s) for s in input().split()]
  edge[a-1].add(b-1)
  edge[b-1].add(a-1)


def dfs(start):
  count=1
  reach=deque([start])
  hito[start]=1
  while reach:
    _from=reach.pop()
    for _to in edge[_from]:
      if not(_to in reach) and hito[_to]==0:
        reach.append(_to)
        count+=1
        hito[_to]=1
  return(count)
 

ans=set()
for h in range(N):
  if hito[h]==0:
    ans.add(dfs(h))
print((max(ans)))

# Optimized solution
N,M=[int(s) for s in input().split()] 
hito=[0 for i in range(N)]
edge=[set() for _ in range(N)]
for i in range(M):
  a,b=[int(s) for s in input().split()]
  edge[a-1].add(b-1)
  edge[b-1].add(a-1)


def dfs(start):
  count=1
  reach=set()
  reach.add(start)
  hito[start]=1
  while reach:
    _from=reach.pop()
    for _to in edge[_from]:
      if not(_to in reach) and hito[_to]==0:
        reach.add(_to)
        count+=1
        hito[_to]=1
  return(count)
 

ans=set()
for h in range(N):
  if hito[h]==0:
    ans.add(dfs(h))
print((max(ans)))
# Original solution
from collections import deque
n,m=list(map(int,input().split()))
f=[[] for _ in range(n)]
for i in range(m):
    a,b=list(map(int,input().split()))
    if not (b-1) in f[a-1]:
        f[a-1].append(b-1)
    if not (a-1) in f[b-1]:
        f[b-1].append(a-1)
chk=[False]*n
q=deque()
ans=0
for i in range(n):
    if chk[i]==True:
        continue
    q.append(i)
    chk[i]=True
    cnt=1
    while q:
        x=q.popleft()
        for nx in f[x]:
            if chk[nx]==True:
                continue
            q.append(nx)
            chk[nx]=True
            cnt+=1
    ans=max(ans,cnt)
print(ans)

# Optimized solution
def resolve():
    #n=int(input())
    #a,b=map(int,input().split())
    #x=list(map(int,input().split()))
    #a=[list(map(lambda x:int(x)%2,input().split())) for _ in range(h)]
    n,m=list(map(int,input().split()))
    f=[set() for _ in range(n)]
    for i in range(m):
        a,b=list(map(int,input().split()))
        f[a-1].add(b-1)
        f[b-1].add(a-1)
    chk=[False]*n
    q=[]
    ans=0
    for i in range(n):
        if chk[i]==True:
            continue
        q.append(i)
        chk[i]=True
        cnt=1
        while q:
            x=q.pop()
            for nx in f[x]:
                if chk[nx]==True:
                    continue
                q.append(nx)
                chk[nx]=True
                cnt+=1
        ans=max(ans,cnt)
    print(ans)

if __name__ == '__main__':
    resolve()