from collections import Counter

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

ab = [tuple(map(int, input().split())) for _ in range(m)]



class UnionFind:

    # まずは最初の状態を作る

    def __init__(self, N):

        # 最初はみんなバラバラ

        self.parent = [i for i in range(N)]

        self.rank = [0] * N

        self.count = 0



    # そのノードの根を返す過程で,集合の要素を根に直接つなぎかえる(木の最適化)

    def root(self, a):

        if self.parent[a] == a:

            return a

        else:

            self.parent[a] = self.root(self.parent[a])

            return self.parent[a]



    # aとbの根が同じ,つまり同じ連結成分内かどうかを返す

    def is_same(self, a, b):

        return self.root(a) == self.root(b)



    # 連結成分同士を効率的に(rankが大きい方を動かさずにrankが小さい方をくっつける)

    def unite(self, a, b):

        ra = self.root(a)

        rb = self.root(b)

        # a, bが同じグループ内にいたから何もしない

        if ra == rb: return

        # 異なるグループにいた場合

        # 短い方をくっつける

        if self.rank[ra] < self.rank[rb]:

            self.parent[ra] = rb

        else:

            self.parent[rb] = ra

            if self.rank[ra] == self.rank[rb]: self.rank[ra] += 1

        self.count += 1



# friendsは友達の数を保持する

uf = UnionFind(n)

for a, b in ab:

    a, b = a-1, b-1

    # aとbが同連結成分内であれば何もする必要がない

    if uf.is_same(a, b): continue

    # 異なれば結合

    uf.unite(a, b)

# 木の高さの最適化

for i in range(n):

    uf.root(i)

tmp = sorted(list(Counter(uf.parent).items()), key=lambda x:x[1])

print((tmp[-1][1]))
from collections import Counter

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

ab = [tuple(map(int, input().split())) for _ in range(m)]



class UnionFind():

    def __init__(self, n):

        self.n = n

        # 要素が根の場合、-(そのグループの要素数)を格納

        self.parents = [-1] * n

        

    # 要素xが属するグループの根を返す    

    def find(self, x):

        if self.parents[x] < 0:

            return x

        else:

            self.parents[x] = self.find(self.parents[x])

            return self.parents[x]

    

    # 要素xが属するグループと要素yが属するグループとを併合する

    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

    

    # 要素xが属するグループのサイズ(要素数)を返す

    def size(self, x):

        return -self.parents[self.find(x)]



    # 要素x, yが同じグループに属すかどうか返す

    def same(self, x, y):

        return self.find(x) == self.find(y)

    

    # 要素xが属するグループに属する要素をリストで返す

    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()}

    

    # printでの表示用, ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す

    def __str__(self):

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



tree = UnionFind(n)

for a, b in ab:

    a,b = a-1, b-1

    if not tree.same(a, b):

        tree.union(a, b)

ans = float("-inf")

for i in range(n):

    ans = max(ans, tree.size(i))

print(ans)
from collections import Counter

n, m = list(map(int, input().split()))
ab = [tuple(map(int, input().split())) for _ in range(m)]


class UnionFind:
    # まずは最初の状態を作る
    def __init__(self, N):
        # 最初はみんなバラバラ
        self.parent = [i for i in range(N)]
        self.rank = [0] * N
        self.count = 0

    # そのノードの根を返す過程で,集合の要素を根に直接つなぎかえる(木の最適化)
    def root(self, a):
        if self.parent[a] == a:
            return a
        else:
            self.parent[a] = self.root(self.parent[a])
            return self.parent[a]

    # aとbの根が同じ,つまり同じ連結成分内かどうかを返す
    def is_same(self, a, b):
        return self.root(a) == self.root(b)

    # 連結成分同士を効率的に(rankが大きい方を動かさずにrankが小さい方をくっつける)
    def unite(self, a, b):
        ra = self.root(a)
        rb = self.root(b)
        # a, bが同じグループ内にいたから何もしない
        if ra == rb:
            return
        # 異なるグループにいた場合
        # 短い方をくっつける
        if self.rank[ra] < self.rank[rb]:
            self.parent[ra] = rb
        else:
            self.parent[rb] = ra
            if self.rank[ra] == self.rank[rb]:
                self.rank[ra] += 1
        self.count += 1


# friendsは友達の数を保持する
uf = UnionFind(n)
for a, b in ab:
    a, b = a - 1, b - 1
    # aとbが同連結成分内であれば何もする必要がない
    if uf.is_same(a, b):
        continue
    # 異なれば結合
    uf.unite(a, b)
# 木の高さの最適化
for i in range(n):
    uf.root(i)
tmp = sorted(list(Counter(uf.parent).items()), key=lambda x: x[1])
print((tmp[-1][1]))

from collections import Counter

n, m = list(map(int, input().split()))
ab = [tuple(map(int, input().split())) for _ in range(m)]


class UnionFind:
    def __init__(self, n):
        self.n = n
        # 要素が根の場合、-(そのグループの要素数)を格納
        self.parents = [-1] * n

    # 要素xが属するグループの根を返す
    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

    # 要素xが属するグループと要素yが属するグループとを併合する
    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

    # 要素xが属するグループのサイズ(要素数)を返す
    def size(self, x):
        return -self.parents[self.find(x)]

    # 要素x, yが同じグループに属すかどうか返す
    def same(self, x, y):
        return self.find(x) == self.find(y)

    # 要素xが属するグループに属する要素をリストで返す
    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()}

    # printでの表示用, ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す
    def __str__(self):
        return "\n".join("{}: {}".format(r, self.members(r)) for r in self.roots())


tree = UnionFind(n)
for a, b in ab:
    a, b = a - 1, b - 1
    if not tree.same(a, b):
        tree.union(a, b)
ans = float("-inf")
for i in range(n):
    ans = max(ans, tree.size(i))
print(ans)

-    # まずは最初の状態を作る -    def __init__(self, N): -        # 最初はみんなバラバラ -        self.parent = [i for i in range(N)] -        self.rank = [0] * N -        self.count = 0 +    def __init__(self, n): +        self.n = n +        # 要素が根の場合、-(そのグループの要素数)を格納 +        self.parents = [-1] * n -    # そのノードの根を返す過程で,集合の要素を根に直接つなぎかえる(木の最適化) -    def root(self, a): -        if self.parent[a] == a: -            return a +    # 要素xが属するグループの根を返す +    def find(self, x): +        if self.parents[x] < 0: +            return x -            self.parent[a] = self.root(self.parent[a]) -            return self.parent[a] +            self.parents[x] = self.find(self.parents[x]) +            return self.parents[x] -    # aとbの根が同じ,つまり同じ連結成分内かどうかを返す -    def is_same(self, a, b): -        return self.root(a) == self.root(b) +    # 要素xが属するグループと要素yが属するグループとを併合する +    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 -    # 連結成分同士を効率的に(rankが大きい方を動かさずにrankが小さい方をくっつける) -    def unite(self, a, b): -        ra = self.root(a) -        rb = self.root(b) -        # a, bが同じグループ内にいたから何もしない -        if ra == rb: -            return -        # 異なるグループにいた場合 -        # 短い方をくっつける -        if self.rank[ra] < self.rank[rb]: -            self.parent[ra] = rb -        else: -            self.parent[rb] = ra -            if self.rank[ra] == self.rank[rb]: -                self.rank[ra] += 1 -        self.count += 1 +    # 要素xが属するグループのサイズ(要素数)を返す +    def size(self, x): +        return -self.parents[self.find(x)] + +    # 要素x, yが同じグループに属すかどうか返す +    def same(self, x, y): +        return self.find(x) == self.find(y) + +    # 要素xが属するグループに属する要素をリストで返す +    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()} + +    # printでの表示用, ルート要素: [そのグループに含まれる要素のリスト]を文字列で返す +    def __str__(self): +        return "\n".join("{}: {}".format(r, self.members(r)) for r in self.roots()) -# friendsは友達の数を保持する -uf = UnionFind(n) +tree = UnionFind(n) -    # aとbが同連結成分内であれば何もする必要がない -    if uf.is_same(a, b): -        continue -    # 異なれば結合 -    uf.unite(a, b) -# 木の高さの最適化 +    if not tree.same(a, b): +        tree.union(a, b) +ans = float("-inf") -    uf.root(i) -tmp = sorted(list(Counter(uf.parent).items()), key=lambda x: x[1]) -print((tmp[-1][1])) +    ans = max(ans, tree.size(i)) +print(ans)