import sys

sys.setrecursionlimit(10**9)



def dfs(G, v, p):

    seen[v] = True

    for nv in G[v]:

        if nv == p: continue

        if seen[nv]: continue

        dfs(G, nv, v)

    

    for c in G[v]:

        if c != p: continue

        sz[p] += (sz[v]+1)



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

ab = []

for _ in range(m):

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

    a, b = a-1, b-1

    if a > b:

        a, b = b, a

    ab.append((a, b))

ab = set(ab)



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

for a, b in ab:

    G[a].append(b)

    G[b].append(a)



seen = [False]*n

sz = [0]*n

for i in range(n):

    if not seen[i]:

        dfs(G, i, -1)



print((max(sz)+1))
import sys

sys.setrecursionlimit(10**7)



def root(x):

    if par[x] == x:

        return x

    else:

        par[x] = root(par[x])

        return par[x]



def unite(x, y):

    x, y = root(x), root(y)

    if x == y: return

    par[x] = y



def is_same(x, y):

    return root(x) == root(y)





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

par = [i for i in range(n)]

for _ in range(m):

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

    a, b = a-1, b-1

    unite(a, b)



cnt = [0]*n

for p in par:

    cnt[root(p)] += 1

print((max(cnt)))
import sys

sys.setrecursionlimit(10**9)


def dfs(G, v, p):
    seen[v] = True
    for nv in G[v]:
        if nv == p:
            continue
        if seen[nv]:
            continue
        dfs(G, nv, v)
    for c in G[v]:
        if c != p:
            continue
        sz[p] += sz[v] + 1


n, m = list(map(int, input().split()))
ab = []
for _ in range(m):
    a, b = list(map(int, input().split()))
    a, b = a - 1, b - 1
    if a > b:
        a, b = b, a
    ab.append((a, b))
ab = set(ab)
G = [[] for _ in range(n)]
for a, b in ab:
    G[a].append(b)
    G[b].append(a)
seen = [False] * n
sz = [0] * n
for i in range(n):
    if not seen[i]:
        dfs(G, i, -1)
print((max(sz) + 1))

import sys

sys.setrecursionlimit(10**7)


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


def unite(x, y):
    x, y = root(x), root(y)
    if x == y:
        return
    par[x] = y


def is_same(x, y):
    return root(x) == root(y)


n, m = list(map(int, input().split()))
par = [i for i in range(n)]
for _ in range(m):
    a, b = list(map(int, input().split()))
    a, b = a - 1, b - 1
    unite(a, b)
cnt = [0] * n
for p in par:
    cnt[root(p)] += 1
print((max(cnt)))

-sys.setrecursionlimit(10**9) +sys.setrecursionlimit(10**7) -def dfs(G, v, p): -    seen[v] = True -    for nv in G[v]: -        if nv == p: -            continue -        if seen[nv]: -            continue -        dfs(G, nv, v) -    for c in G[v]: -        if c != p: -            continue -        sz[p] += sz[v] + 1 +def root(x): +    if par[x] == x: +        return x +    else: +        par[x] = root(par[x]) +        return par[x] + + +def unite(x, y): +    x, y = root(x), root(y) +    if x == y: +        return +    par[x] = y + + +def is_same(x, y): +    return root(x) == root(y) -ab = [] +par = [i for i in range(n)] -    if a > b: -        a, b = b, a -    ab.append((a, b)) -ab = set(ab) -G = [[] for _ in range(n)] -for a, b in ab: -    G[a].append(b) -    G[b].append(a) -seen = [False] * n -sz = [0] * n -for i in range(n): -    if not seen[i]: -        dfs(G, i, -1) -print((max(sz) + 1)) +    unite(a, b) +cnt = [0] * n +for p in par: +    cnt[root(p)] += 1 +print((max(cnt)))