class UnionFind: # simple

    def __init__(self, n):

        self.prsz = [-1] * n # parent ' size

    def find(self, v): # root

        if self.prsz[v] < 0: return v

        else:

            self.prsz[v] = self.find(self.prsz[v])

            return self.prsz[v]

    def union(self, v, u): # unite

        v = self.find(v); u = self.find(u)

        if v == u: return False

        if self.g_size(v) < self.g_size(u): v, u = u, v

        self.prsz[v] += self.prsz[u]

        self.prsz[u] = v

        return True

    def g_size(self, v): return -self.prsz[self.find(v)]



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

uf = UnionFind(n)

for _ in range(m): uf.union(*[int(x)-1 for x in input().split()]) # unite

ans = 0

for i in range(n): ans = max(ans, uf.g_size(i))

print(ans)

class UnionFind: # simple

    def __init__(self, n):

        self.prsz = [-1] * n # parent ' size

    def find(self, v): # root

        if self.prsz[v] < 0: return v

        else:

            self.prsz[v] = self.find(self.prsz[v])

            return self.prsz[v]

    def union(self, v, u): # unite

        v = self.find(v); u = self.find(u)

        if v == u: return False

        if self.prsz[v] > self.prsz[u]: v, u = u, v # size(v) < size(u)

        self.prsz[v] += self.prsz[u]

        self.prsz[u] = v

        return True

    def size(self, v): return -self.prsz[self.find(v)]



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

uf = UnionFind(n)

for _ in range(m): uf.union(*[int(x)-1 for x in input().split()]) # unite

ans = 0

for i in range(n): ans = max(ans, uf.size(i))

print(ans)

class UnionFind:  # simple
    def __init__(self, n):
        self.prsz = [-1] * n  # parent ' size

    def find(self, v):  # root
        if self.prsz[v] < 0:
            return v
        else:
            self.prsz[v] = self.find(self.prsz[v])
            return self.prsz[v]

    def union(self, v, u):  # unite
        v = self.find(v)
        u = self.find(u)
        if v == u:
            return False
        if self.g_size(v) < self.g_size(u):
            v, u = u, v
        self.prsz[v] += self.prsz[u]
        self.prsz[u] = v
        return True

    def g_size(self, v):
        return -self.prsz[self.find(v)]


n, m = list(map(int, input().split()))
uf = UnionFind(n)
for _ in range(m):
    uf.union(*[int(x) - 1 for x in input().split()])  # unite
ans = 0
for i in range(n):
    ans = max(ans, uf.g_size(i))
print(ans)

class UnionFind:  # simple
    def __init__(self, n):
        self.prsz = [-1] * n  # parent ' size

    def find(self, v):  # root
        if self.prsz[v] < 0:
            return v
        else:
            self.prsz[v] = self.find(self.prsz[v])
            return self.prsz[v]

    def union(self, v, u):  # unite
        v = self.find(v)
        u = self.find(u)
        if v == u:
            return False
        if self.prsz[v] > self.prsz[u]:
            v, u = u, v  # size(v) < size(u)
        self.prsz[v] += self.prsz[u]
        self.prsz[u] = v
        return True

    def size(self, v):
        return -self.prsz[self.find(v)]


n, m = list(map(int, input().split()))
uf = UnionFind(n)
for _ in range(m):
    uf.union(*[int(x) - 1 for x in input().split()])  # unite
ans = 0
for i in range(n):
    ans = max(ans, uf.size(i))
print(ans)

-        if self.g_size(v) < self.g_size(u): -            v, u = u, v +        if self.prsz[v] > self.prsz[u]: +            v, u = u, v  # size(v) < size(u) -    def g_size(self, v): +    def size(self, v): -    ans = max(ans, uf.g_size(i)) +    ans = max(ans, uf.size(i))