Problem:
 Score : 400 points    Problem Statement There are N persons called Person 1 through Person N .  You are given M facts that "Person A_i and Person B_i are friends." The same fact may be given multiple times.  If X and Y are friends, and Y and Z are friends, then X and Z are also friends. There is no friendship that cannot be derived from the M given facts.  Takahashi the evil wants to divide the N persons into some number of groups so that every person has no friend in his/her group.  At least how many groups does he need to make?      Constraints  2 \leq N \leq 2\times 10^5  0 \leq M \leq 2\times 10^5  1\leq A_i,B_i\leq N  A_i \neq B_i         Input Input is given from Standard Input in the following format:  N  M  A_1  B_1  \vdots  A_M  B_M       Output Print the answer.        Sample Input 1 5 3
1 2
3 4
5 1      Sample Output 1 3  Dividing them into three groups such as \{1,3\} , \{2,4\} , and \{5\} achieves the goal.       Sample Input 2 4 10
1 2
2 1
1 2
2 1
1 2
1 3
1 4
2 3
2 4
3 4      Sample Output 2 4       Sample Input 3 10 4
3 1
4 1
5 9
2 6      Sample Output 3 3

Solution (Python):
def A():
    d, t, s = map(int, input().split())
    print("Yes" if t*s>=d else "No")

def B():
    s = input()
    t = input()
    sa = len(s) - len(t)
    ret = 10000000000
    for i in range(sa+1):
        cnt = 0
        for j in range(len(t)):
            if s[j+i] != t[j]: cnt += 1
        ret = min(ret, cnt)
    print(ret)

def C():
    int(input())
    A = list(map(int, input().split()))
    S = sum(A)
    T = 0
    for e in A:
        T += e*e
    print((S * S - T)//2)

class UF:
    def __init__(self, N):
        self.N = N
        self.sz = [1] * N
        self.par = [i for i in range(N)]
        self.d = [1] * N

    def find(self, x):
        if self.par[x] == x: return x
        self.par[x] = self.find(self.par[x])
        return self.par[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y: return False
        if self.d[y] > self.d[x]:
            self.par[x] = y
            self.sz[y] += self.sz[x]
        else:
            self.par[y] = x
            self.sz[x] += self.sz[y]
            if self.d[x] == self.d[y]: self.d[x] += 1

def D():
    n, m = map(int, input().split())
    uf = UF(n+1)
    for i in range(m):
        a, b = map(int, input().split())
        uf.unite(a, b)
    print(max(uf.sz))

D()

Solution (Python):
def A():
    d, t, s = map(int, input().split())
    print("Yes" if t*s>=d else "No")

def B():
    s = input()
    t = input()
    sa = len(s) - len(t)
    ret = 10000000000
    for i in range(sa+1):
        cnt = 0
        for j in range(len(t)):
            if s[j+i] != t[j]: cnt += 1
        ret = min(ret, cnt)
    print(ret)

def C():
    int(input())
    A = list(map(int, input().split()))
    S = sum(A)
    T = 0
    for e in A:
        T += e*e
    print((S * S - T)//2)

class UF:
    def __init__(self, N):
        self.N = N
        self.sz = [1] * N
        self.par = [i for i in range(N)]
        self.d = [1] * N

    def find(self, x):
        if self.par[x] == x: return x
        self.par[x] = self.find(self.par[x])
        return self.par[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y: return False
        if self.d[y] > self.d[x]:
            self.par[x] = y
            self.sz[y] += self.sz[x]
        else:
            self.par[y] = x
            self.sz[x] += self.sz[y]
            if self.d[x] == self.d[y]: self.d[x] += 1

def D():
    n, m = map(int, input().split())
    uf = UF(n+1)
    for i in range(m):
        a, b = map(int, input().split())
        uf.unite(a, b)
    print(max(uf.sz))

D()

Solution (Python):
import networkx as nx
n,m=map(int, input().split())
uf=nx.utils.UnionFind()
for _ in range(m):
    a,b=map(int, input().split())
    uf.union(a, b)
ans=1
for i in uf.to_sets():
    ans=max(ans,len(i))
print(ans)

Solution (Python):
class UnionFind:
    def __init__(self, n=0):
        self.d = [-1]*n
    def find(self, x):
        if self.d[x] < 0:
            return x
        else:
            self.d[x] = self.find(self.d[x])
            return self.d[x]
    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.d[x] > self.d[y]:
            x, y = y, x
        self.d[x] += self.d[y]
        self.d[y] = x
        return True
    def same(self, x, y):
        return self.find(x) == self.find(y)
    def size(self, x):
        return -self.d[self.find(x)]


n, m = map(int, input().split())
uf = UnionFind(n)

for _ in range(m):
    a, b = map(int, input().split())
    uf.unite(a-1, b-1)

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

print(ans)

Solution (Python):
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()))
uf = UnionFind(n)

for i in range(m):
    a,b = list(map(int, input().split()))
    uf.union(a-1,b-1)

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

print(ans)

Solution (Python):
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 issame(self, x, y):
        return self.find[x] == self.find(y)


'''
参考
https://qiita.com/K_SIO/items/03ff1fc1184cb39674aa
'''
if __name__ == '__main__':
    N, M = map(int, input().split())
    uf = UnionFind(N)

    for _ in range(M):
        A, B = map(int, input().split())
        uf.union(A-1, B-1)
    
    ans = 0

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

Solution (Python):
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 roots(self):
    return [i for i,x in enumerate(self.parents) if x<0]

N,M=map(int,input().split())
uf=UnionFind(N)
for _ in range(M):
  a,b=map(int,input().split())
  uf.unite(a-1,b-1)
ans=0
for r in uf.roots():
  s=uf.size(r)
  ans=max(ans,s)
print(ans)

Solution (Python):
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

def unite(x,y):
  x = find(x)
  y = find(y)
    
  if x == y:
    return False
  else:
    if par[x] > par[y]:
      x,y = y,x
    par[x] += par[y]
    par[y] = x
    return True

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

def size(x):
  return -par[find(x)]

N,M=map(int,input().split())
par = [-1]*N
for _ in range(M):
  a,b=map(int,input().split())
  unite(a-1,b-1)
print(-min(par))

Solution (Python):
from networkx.utils import UnionFind as UF
n,m=map(int, input().split())
uf=UF()
for _ in range(m):
    a,b=map(int, input().split())
    uf.union(a, b)
ans=1
for i in uf.to_sets():
    ans=max(ans,len(i))
print(ans)

Solution (Python):
import networkx as nx
n,m=map(int, input().split())
uf=nx.utils.UnionFind()
for _ in range(m):
    a,b=map(int, input().split())
    uf.union(a, b)
ans=1
for i in uf.to_sets():
    ans=max(ans,len(i))
print(ans)

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


class UnionFind(object):
    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]


uf = UnionFind(N)
for a, b in AB:
    uf.union(a - 1, b - 1)

max_ = 0
roots = uf.roots()

for r in roots:
    max_ = max(max_, uf.size(r))

print(max_)

Solution (Python):
N,M = map(int, input().split())

class UnionFind:
    def __init__(self, N):
        self.root = list(range(N + 1))
        self.size = [1] * (N + 1)

    def __getitem__(self, x):
        root = self.root
        while root[x] != x:
            root[x] = root[root[x]]
            x = root[x]
        return x

    def merge(self, x, y):
        x = self[x]
        y = self[y]
        if x == y:
            return
        sx, sy = self.size[x], self.size[y]
        if sx < sy:
            x, y = y, x
            sx, sy = sy, sx
        self.root[y] = x
        self.size[x] += sy

    def find_max(self):
        return max(self.size)

uf = UnionFind(N)

answer = []
append = answer.append
merge = uf.merge

for i in range(M):
    a,b = map(int, input().split())
    merge(a,b)
print(uf.find_max())

Solution (Python):

printn = lambda x: print(x,end='')
inn = lambda : int(input())
inl   = lambda: list(map(int, input().split()))
inm   = lambda:      map(int, input().split())
ins = lambda : input().strip()
DBG = True 
BIG = 10**18
R = 10**9 + 7


def ddprint(x):
  if DBG:
    print(x)





class Unionfind:

  def __init__(s,n):
    s.sz = [1] * n
    s.ances = [i for i in range(n)]

  def root(s,x):
    a = []
    y = x
    while s.ances[y] != y:
      a.append(y)
      y = s.ances[y]
    for z in a:
      s.ances[z] = y
    return y

  def conn(s,x,y):
    i = s.root(x)
    j = s.root(y)
    if i==j:
      return
    
    k  = j if (s.sz[i]<s.sz[j]) else i
    if k==j:
      s.ances[i] = j
    else:
      s.ances[j] = i
    s.sz[k] = s.sz[i] + s.sz[j]



n,m = inm()
uf = Unionfind(n)
for i in range(m):
    a,b = inm()
    uf.conn(a-1,b-1)
h = {}
x = 0
for i in range(n):
    r = uf.root(i)
    if r not in h:
        h[r] = 1
    else:
        h[r] += 1
    x = max(x,h[r])
print(x)

Solution (Python):
N, M = (int(d) for d in input().split())

C = [set() for i in range(N+1)]
for i in range(M):
    A, B = (int(d) for d in input().split())
    C[A].update([B])
    C[B].update([A])


seen = set()
G = []

for i in range(1, N+1):
    if i in seen:
        continue

    
    G.append(set())

    
    Q = [i]
    G[-1].update(Q)
    seen.update(Q)

    while len(Q) > 0:
        

        I = Q.pop(0)
        J = C[I].difference(seen)
        Q += list(J)
        G[-1].update(J)

        seen.update(J)

print(max([len(g) for g in G]))

Solution (Python):
import sys


def input():
    return sys.stdin.readline()[:-1]


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 = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
    a, b = 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)

Solution (Python):
N, M = list(map(int, input().split()))
A = [0] * M
B = [0] * M
R = [0] * N
for i in range(N):
    R[i] = set()

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

stack = set()
visited = set()
max_groups = 0

for i in range(N):
    if not i in visited:
        stack.add(i)
        groups = 0
        while True:
            current = stack.pop()
            visited.add(current)
            groups += 1
            stack |= (R[current] - visited)
            if not stack:
                break
        max_groups = max(max_groups,groups)

print(max_groups)

Solution (Python):
import networkx as nx
import sys

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

G = nx.Graph()

n, m = map(int, readline().split())
if m == 0:
    print(1)
    sys.exit()
for i in range(m):
    a, b = map(int, readline().split())
    G.add_edge(a, b)

largest_cc = max(nx.connected_components(G), key=len)
print(len(largest_cc))

Solution (Python):
import networkx as nx
import sys

G = nx.Graph()

n, m = map(int, input().split())
if m == 0:
    print(1)
    sys.exit()
for i in range(m):
    a, b = map(int, input().split())
    G.add_edge(a, b)

largest_cc = max(nx.connected_components(G), key=len)
print(len(largest_cc))

Solution (Python):
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.par = [i for i in range(n)]
        self.rank = [0 for i in range(n)]
        self.siz = [1 for i in range(n)]

    def find(self, x):
        if self.par[x] == x:
            return x
        self.par[x] = self.find(self.par[x])
        return self.find(self.par[x])

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

        if x == y:
            return

        if self.rank[x] > self.rank[y]:
            self.par[y] = x
            self.siz[x] += self.siz[y]
        else:
            self.par[x] = y
            self.siz[y] += self.siz[x]
            if self.rank[x] == self.rank[y]:
                self.rank[y] += 1
    
    def same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        return self.siz[self.find(x)]
    
n, m = map(int, input().split())
uf = UnionFind(n)
for i in range(m):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    uf.unite(a, b)

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

print(res)

Solution (Python):

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=map(int,input().split())
uf=UnionFind(n)
for i in range(m):
    a,b=map(int,input().split())
    uf.unite(a-1,b-1)
print(-min(uf.parents))

Solution (Python):
class UnionFind():
    """ Union-Find木の実装（ランクあり） """
    def __init__(self, n):
        self.n = n
        self.parent = [-1]*(n+1)    
        self.rank   = [0]*(n+1)     

    def root(self, x):
        """ 木の根を求める """
        if self.parent[x] < 0:      
            return x
        else:
            self.parent[x] = self.root(self.parent[x])  
            return self.parent[x]
            
    def unite(self, x, y):
        """ xとyの属する集合を併合 """
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return 0
        elif self.rank[x] > self.rank[y]:
            self.parent[x] += self.parent[y]
            self.parent[y] = x
        else:
            self.parent[y] += self.parent[x]
            self.parent[x] = y
            if self.rank[x] == self.rank[y]:
                self.rank[y] += 1

    def isSame(self, x, y):
        """ xとyが同じ集合に属するか否か """
        return self.root(x) == self.root(y) or x==y
    
    def size(self, x):
        """ xと同じ集合に属する数 """
        return -self.parent[self.root(x)]


N, M = map(int, input().split())
uf = UnionFind(N)
for i in range(M):
    A, B = map(int, input().split())
    A -= 1; B -= 1
    uf.unite(A, B)
ans = 0
for i in range(N):
    ans = max(ans, uf.size(i))
print(ans)

Solution (Python):
from sys import stdin
nii=lambda:map(int,stdin.readline().split())
lnii=lambda:list(map(int,stdin.readline().split()))

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 same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        return -self.parents[self.find(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()}

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

n,m=nii()
uf=UnionFind(n)
for i in range(m):
  a,b=nii()
  a-=1
  b-=1
  uf.union(a,b)

root=uf.roots()
ans=0
for i in root:
  ans=max(ans,uf.size(i))

print(ans)

Solution (Python):
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 = map(int, input().split())
    uf = UnionFind(n)

    for _ in range(m):
        a, b = map(int, input().split())
        uf.union(a-1, b-1)
    
    sizes = [uf.size(i) for i in range(n)]
    
    print(max(sizes))


if __name__ == '__main__':
    main()

Solution (Python):
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 = map(int, input().split())
    uf = UnionFind(n)

    for _ in range(m):
        a, b = map(int, input().split())
        uf.union(a-1, b-1)
    
    ans = 0
    for i in range(n):
        ans = max(ans, uf.size(i))
    
    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
from collections import deque


def main():
    n, m = map(int, input().split())
    is_checked = [False for _ in range(n+1)]
    edges = [[] for _ in range(n+1)]
    ans = 0

    for _ in range(m):
        a, b = map(int, input().split())
        edges[a].append(b)
        edges[b].append(a)

    for ni in range(n):
        if is_checked[ni]:
            continue
        is_checked[ni] = True
        q = deque([ni])
        depth = 0
        while len(q) > 0:
            p = q.popleft()
            for e in edges[p]:
                if not is_checked[e]:
                    is_checked[e] = True
                    q.append(e)
            depth += 1

        ans = max(ans, depth)

    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
class Unionfind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * (n+1)
        
    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 = map(int, input().split())
uf = Unionfind(N)

for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    uf.union(a, b)

ans = [uf.size(i) for i in range(N)]
print(max(ans))

Solution (Python):
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 = map(int,input().split())
uf = UnionFind(n)
for i in range(m):
    a, b = map(int, input().split())
    uf.union(a-1, b-1)
box = []
for i in range(n):
    box.append(uf.size(i))
print(max(box))

Solution (Python):
class UnionFind():
    
    
    def __init__(self, n):
        self.n = n
        
        
        self.root = [-1]*(n+1)
        
        self.rnk = [0]*(n+1)

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

    
    def Unite(self, x, y):
        
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        
        if (x == y):
            return 
        
        
        elif (self.rnk[x] > self.rnk[y]):
            self.root[x] += self.root[y]
            self.root[y] = x

        else:
            self.root[y] += self.root[x]
            self.root[x] = y
        
        if(self.rnk[x] == self.rnk[y]):
            self.rnk[y] += 1

    
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    
    def Count(self, x):
        return -self.root[self.Find_Root(x)]


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

uni=UnionFind(N)
for i in range(M):
    a,b=map(int, input().split())
    uni.Unite(a-1,b-1)
ans=0
for i in range(N):
    ans=max(ans, uni.Count(i))
print(ans)

Solution (Python):

import sys, math, heapq
from itertools import permutations, combinations
from collections import defaultdict, Counter, deque
from math import factorial, gcd
from bisect import bisect_left, bisect_right

sys.setrecursionlimit(10 ** 7)
MOD = 10 ** 9 + 7
input = lambda: sys.stdin.readline()[:-1]
pl = lambda x: print(*x, sep="\n")

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


class UnionFind:
    def __init__(self, n):
        self.par = [i for i in range(n)]
        self.rank = [0] * (n)
        self.size = [1] * (n)

    def find(self, x):
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]

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

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x != y:
            if self.rank[x] < self.rank[y]:
                x, y = y, x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
            self.par[y] = x
            self.size[x] += self.size[y]

    def get_size(self, x):
        x = self.find(x)
        return self.size[x]


uni = UnionFind(N)
for ab in AB:
    a, b = ab
    uni.union(a - 1, b - 1)

sizemax = 0
for n in range(N):
    size = uni.get_size(n)
    sizemax = max(sizemax, size)
print(sizemax)

Solution (Python):
class UnionFind:

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

    def find(self, x):
        if self.parents[x] < 0:
            return x
        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    

N, M = map(int, input().split())
uf = UnionFind(N)

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

ans = 0
for i in range(N):
    ans = max(ans, -uf.parents[i])
print(ans)

Solution (Python):
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=map(int,input().split())
uf=UnionFind(n)
for i in range(m):
  a,b=map(int,input().split())
  uf.union(a-1,b-1)
ans=0
for i in range(n):
  ans=max(ans,uf.size(i))
print(ans)