import sys,heapq

input = sys.stdin.buffer.readline



sys.setrecursionlimit(10**7)





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

edge = [[] for _ in range(n)]



for _ in range(m):

    a,b = list(map(int,input().split()))

    edge[a-1].append(b-1)

    edge[b-1].append(a-1)



#True:訪問済み False:未訪問

flag = [False]*n



def dfs(now):

    if flag[now]:

        return 0

    

    flag[now] = True



    size = 0

    for nxt in edge[now]:

        if not flag[nxt]:

            size += dfs(nxt)



    return size + 1



res = 0



for i in range(n):

    if flag[i]:

        continue

    res = max(res,dfs(i))



print(res)

#Union Find



#xの根を求める

def find(x):

    if par[x] < 0:

        return x

    else:

        tank = []

        while par[x] >= 0:

            tank.append(x)

            x = par[x]

        for elt in tank:

            par[elt] = x

        return x

#xとyの属する集合の併合

def unite(x,y):

    x = find(x)

    y = find(y)

    

    if x == y:

        return False

    else:

        #sizeの大きいほうがx

        if par[x] > par[y]:

            x,y = y,x

        par[x] += par[y]

        par[y] = x

        return True



#xとyが同じ集合に属するかの判定

def same(x,y):

    return find(x) == find(y)



#xが属する集合の個数

def size(x):

    return -par[find(x)]



import sys

input = sys.stdin.buffer.readline

 

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



#初期化

#根なら-size,子なら親の頂点

par = [-1]*n



 

for _ in range(m):

    a,b = list(map(int,input().split()))

    unite(a-1,b-1)

 

res = 0

for e in par:

    if e < 0:

        res = max(res,-e)

print(res)
import sys, heapq

input = sys.stdin.buffer.readline
sys.setrecursionlimit(10**7)
n, m = list(map(int, input().split()))
edge = [[] for _ in range(n)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    edge[a - 1].append(b - 1)
    edge[b - 1].append(a - 1)
# True:訪問済み False:未訪問
flag = [False] * n


def dfs(now):
    if flag[now]:
        return 0
    flag[now] = True
    size = 0
    for nxt in edge[now]:
        if not flag[nxt]:
            size += dfs(nxt)
    return size + 1


res = 0
for i in range(n):
    if flag[i]:
        continue
    res = max(res, dfs(i))
print(res)

# Union Find
# xの根を求める
def find(x):
    if par[x] < 0:
        return x
    else:
        tank = []
        while par[x] >= 0:
            tank.append(x)
            x = par[x]
        for elt in tank:
            par[elt] = x
        return x


# xとyの属する集合の併合
def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return False
    else:
        # sizeの大きいほうがx
        if par[x] > par[y]:
            x, y = y, x
        par[x] += par[y]
        par[y] = x
        return True


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


# xが属する集合の個数
def size(x):
    return -par[find(x)]


import sys

input = sys.stdin.buffer.readline
n, m = list(map(int, input().split()))
# 初期化
# 根なら-size,子なら親の頂点
par = [-1] * n
for _ in range(m):
    a, b = list(map(int, input().split()))
    unite(a - 1, b - 1)
res = 0
for e in par:
    if e < 0:
        res = max(res, -e)
print(res)

-import sys, heapq +# Union Find +# xの根を求める +def find(x): +    if par[x] < 0: +        return x +    else: +        tank = [] +        while par[x] >= 0: +            tank.append(x) +            x = par[x] +        for elt in tank: +            par[elt] = x +        return x + + +# xとyの属する集合の併合 +def unite(x, y): +    x = find(x) +    y = find(y) +    if x == y: +        return False +    else: +        # sizeの大きいほうがx +        if par[x] > par[y]: +            x, y = y, x +        par[x] += par[y] +        par[y] = x +        return True + + +# xとyが同じ集合に属するかの判定 +def same(x, y): +    return find(x) == find(y) + + +# xが属する集合の個数 +def size(x): +    return -par[find(x)] + + +import sys -sys.setrecursionlimit(10**7) -edge = [[] for _ in range(n)] +# 初期化 +# 根なら-size,子なら親の頂点 +par = [-1] * n -    edge[a - 1].append(b - 1) -    edge[b - 1].append(a - 1) -# True:訪問済み False:未訪問 -flag = [False] * n - - -def dfs(now): -    if flag[now]: -        return 0 -    flag[now] = True -    size = 0 -    for nxt in edge[now]: -        if not flag[nxt]: -            size += dfs(nxt) -    return size + 1 - - +    unite(a - 1, b - 1) -for i in range(n): -    if flag[i]: -        continue -    res = max(res, dfs(i)) +for e in par: +    if e < 0: +        res = max(res, -e)