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):
class MyUnionFind():
    __slots__ = ["par", "rank", "size"]

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

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

        ret = self.find(self.par[c])
        self.par[c] = ret
        return ret

    def union(self, x, y):
        xr = self.find(x)
        yr = self.find(y)
        if xr == yr:
            return

        if self.rank[yr] > self.rank[xr]:
            self.par[xr] = yr
            self.size[yr] += self.size[xr]
        else:
            self.par[yr] = xr
            self.size[xr] += self.size[yr]
            if self.rank[xr] == self.rank[yr]:
                self.rank[xr] += 1



def main():
    N, M = map(int, input().split())
    uf = MyUnionFind(N)
    for i in range(M):
        a, b = map(int, input().split())
        uf.union(a, b)

    print(max(uf.size))

if __name__ == '__main__':
    main()

Solution (Python):
class UnionFind:
    def __init__(self, num):
        self.parent = [-1] * num

    def find(self, node):
        if self.parent[node] < 0:
            return node
        self.parent[node] = self.find(self.parent[node])
        return self.parent[node]

    def union(self, node1, node2):
        node1 = self.find(node1)
        node2 = self.find(node2)
        if node1 == node2:
            return
        if self.parent[node1] > self.parent[node2]:
            node1, node2 = node2, node1
        self.parent[node1] += self.parent[node2]
        self.parent[node2] = node1
        return

    def same(self, node1, node2):
        return self.find(node1) == self.find(node2)

    def size(self, x):
        return -self.parent[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.union(a, b)

ans = float(0)

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

print(ans)

Solution (Python):
import sys

def IS(): return sys.stdin.readline().rstrip()
def II(): return int(IS())
def MII(): return list(map(int, IS().split()))
def MIIZ(): return list(map(lambda x: x-1, MII()))

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 count_member_nums(self):
        return [len(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 = MII()
    group = [MIIZ() for _ in range(m)]
    uf = UnionFind(n)
    for a, b in group:
        uf.union(a, b)
    print(abs(sorted(uf.parents)[0]))


if __name__ == '__main__':
    main()

Solution (Python):
import sys
from collections import deque

input = sys.stdin.readline

N, M = map(int, input().split())
relations = [[] for _ in range(N)]
for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    relations[a].append(b)
    relations[b].append(a)

ans = 0
visited = set()
for i in range(N):
    q = deque()
    q.append(i)
    start = len(visited)
    while q:
        pos = q.popleft()
        if pos in visited:
            continue
        visited.add(pos)
        for n_pos in relations[pos]:
            if n_pos in visited:
                continue
            q.appendleft(n_pos)
    end = len(visited)
    ans = max(ans, end - start)

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 _ in range(m):
    a, b = map(int, input().split())
    a-=1
    b-=1
    uf.union(a, b)

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

print(result)

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)
    





print(min(uf.parents)*(-1))

Solution (Python):
from collections import Counter

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())
group = UnionFind(N)

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

print(max([group.size(x) for x in group.roots()]))

Solution (Python):
import sys
sys.setrecursionlimit(100000000)

n, m = map(int, input().split())
graph = [[] for _ in range(n+1)]
visited = [False for _ in range(n+1)]



def dfs(node):
    visited[node] = True
    ret = 0
    for child in graph[node]:
        if not visited[child]:
            ret += dfs(child)
    return ret + 1


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

rets = []
for node in range(1, n+1):
    if not visited[node] :
        counts = dfs(node)
        rets.append(counts)
print(max(rets))

Solution (Python):
class UnionFind():
  def __init__(self, n):
    self.n = n
    self.root = [-1] * (n + 1)
    self.rank = [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.rank[x] > self.rank[y]:
      self.root[x] += self.root[y]
      self.root[y] = x
    
    else:
      self.root[y] += self.root[x]
      self.root[x] = y

      if self.rank[x] == self.rank[y]:
        self.rank[y] += 1
    
  def same(self, x, y):
    return self.find_root(x) == self.find_root(y)

  def size(self, x):
    return -self.root[self.find_root(x)]

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

tree = UnionFind(N)

for i in range(M):
  a, b = list(map(int, input().split()))
  tree.unite(a, b)
res = 0

for i in range(N):
  res = max(res, tree.size(i))

print(res)

Solution (Python):
class disjoint_set:
    def __init__(self,num):

        self.array=[0]+[[i,0,1] for i in range(1,num+1)]  
    
    def union(self,a,b):
        
        ''' a and b are the vertices that we want to connect them to each other '''
        
        a=self.find(a) 
        b=self.find(b) 
    
        if a==b:
            
            return False
    

        

        if self.array[a][1] > self.array[b][1] :
            self.array[b][0]=a
            self.array[a][2]+=self.array[b][2]
        
        elif self.array[a][1] < self.array[b][1] :
            self.array[a][0]=b
            self.array[b][2]+=self.array[a][2]

        else:
            self.array[a][0]=b
            self.array[b][1]+=1
            self.array[b][2]+=self.array[a][2]
        return True
            
    def find(self,a):
        p=[]
        while self.array[a][0]!=a :
            p.append(a)
            a=self.array[a][0]
        for i in p:
            self.array[i][0]=a
        return a
        

n,m=map(int ,input().split())
friend = disjoint_set(n)
for _ in range(m):
    x,y=map(int ,input().split())
    friend.union(x,y)

ans=-10
for i in range(1,n+1):
    if friend.array[i][0]==i :
        ans=max(ans,friend.array[i][2])

print(ans)

Solution (Python):
    
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]

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

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

n, m = map(int, input().split())
ab = []
for _ in range(m):
    a, b = map(int, input().split())
    ab.append([a-1, b-1])
par = [-1]*n

icnt=0
for i in range(m):
    unite(ab[i][0],ab[i][1])
    
szmax=0    
for i in range(n):
    sz=size(i)

    szmax=max(szmax,sz)
    
print(szmax)

Solution (Python):
n,m = map(int,input().split())
t = [0]*n
q = []
r = 1
for i in range(n):
    q.append([])
for i in range(m):
    a,b = map(int,input().split())
    q[a-1].append(b-1)
    q[b-1].append(a-1)
num = 0
for i in range(n):
    if(t[i] == 0):
        num += 1
        cnt = 0
        stc = [i]
        while(len(stc) > cnt):
            x = stc[cnt]
            for j in range(len(q[x])):
                if(t[q[x][j]] == 0):
                    t[q[x][j]] = num
                    stc.append(q[x][j])
            cnt += 1
        r = max(cnt-1,r)
print(r)

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())
    a-=1; b-=1
    uf.union(a, b)

print(max([uf.size(i) for i in uf.roots()]))

Solution (Python):


import copy
import random
import bisect 
import fractions 
import math
import sys
import collections
from decimal import Decimal 

mod = 10**9+7
sys.setrecursionlimit(mod) 

d = collections.deque()
def LI(): return list(map(int, sys.stdin.readline().split()))


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)]

"""
example

N = "number of nodes"
uf = UnionFind(N)

for a,b in range(M):
    uf.Unite(a, b)


"""


N, M = LI()
ab = []
for i in range(M):
    a, b = LI()
    a -= 1
    b -= 1
    ab.append((a,b))

uf = UnionFind(N)
for (a, b) in ab:
    uf.Unite(a,b)

cnt = 0
for i in range(N):
    cnt = max(cnt, uf.Count(i))

print(cnt)

Solution (Python):
n,m = map(int, input().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 size(self, x):
        return -self.parents[self.find(x)]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

uf = UnionFind(n)

for i in range(m):
    a,b = map(int, input().split())
    a -=1
    b -=1
    uf.union(a,b)
    
res = [0]
for j in  uf.roots():
    res.append(uf.size(j))
print(max(res))

Solution (Python):
class UnionFind():
    '''
    グループ分けを木構造で管理するデータ構造
    以下の二点を高速で行うことができるのがメリット．
    ・要素xと要素yが同じグループに属するかどうかを判定したい
        → 要素xの根と要素yの根が同じならば同じグループ，
          要素xの根と要素yの根が同じでないならば異なるグループ
          にあることが分かる．
    ・要素xと要素yが別のグループに属する場合，
        要素xの属するグループと要素yの属するグループを併合する．
    '''

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

    def size(self, x):
        return -self.parents[self.find(x)]  

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]



def resolve():
    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):
        s = uf.size(i)
        if ans < s:
            ans = s

    print(ans)

resolve()

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

ad = {}
for n in range(N):
    ad[n+1]=[]

for m in range(M):
    a,b = list(map(int,input().split()))
    ad[a].append(b)
    ad[b].append(a)
    
from collections import deque
    
color = {}
for n in range(N):
    color[n+1] = -1

depth = {}
for n in range(N):
    depth[n+1] = -1
    
group = {}


    
group_= 0
for p in range(1,N+1):
    if color[p] != -1: 
        continue
    elif color[p] == -1: 
        start = p
        color[start] = 0
        que = deque([start])
        visit = deque([])
        group_+=1
        group[group_] = [start]

    depth[start] = 0
    while len(que) > 0:
        start = que[0]

        for v in ad[start]:

            if color[v] == -1:
                que.append(v)
                color[v] = 0
                depth[v] = depth[start]+1
                group[group_].append(v)
                
        color[start] = 1
        visit.append(que.popleft())

ans=0
for g in group.keys():
    if len(group[g]) > ans:
        ans=len(group[g])
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)



max_num = 0
for root in uf.roots():
    max_num = max(max_num, uf.size(root))
print(max_num)

Solution (Python):
import sys
sys.setrecursionlimit(1 << 25)
readline = sys.stdin.buffer.readline
read = sys.stdin.readline  
ra = range
enu = enumerate


def exit(*argv, **kwarg):
    print(*argv, **kwarg)
    sys.exit()


def mina(*argv, sub=1): return list(map(lambda x: x - sub, argv))



def a_int(): return int(readline())


def ints(): return list(map(int, readline().split()))


def read_col(H):
    '''H is number of rows
    A列、B列が与えられるようなとき
    ex1)A,B=read_col(H)    ex2) A,=read_col(H) 
    ret = []
    for _ in range(H):
        ret.append(list(map(int, readline().split())))
    return tuple(map(list, zip(*ret)))


def read_tuple(H):
    '''H is number of rows'''
    ret = []
    for _ in range(H):
        ret.append(tuple(map(int, readline().split())))
    return ret


def read_matrix(H):
    '''H is number of rows'''
    ret = []
    for _ in range(H):
        ret.append(list(map(int, readline().split())))
    return ret
    


class UnionFind:
    def __init__(self, N):
        self.N = N  
        self.n_groups = N  
        
        self.parent = [-1] * N  

    def root(self, A):
        
        
        if (self.parent[A] < 0):
            return A
        self.parent[A] = self.root(self.parent[A])  
        return self.parent[A]

    def size(self, A):
        
        return -self.parent[self.root(A)]

    def unite(self, A, B):
        
        
        A = self.root(A)
        B = self.root(B)

        
        if (A == B):
            return False

        
        if (self.size(A) < self.size(B)):
            A, B = B, A

        
        self.parent[A] += self.parent[B]  
        self.parent[B] = A  
        self.n_groups -= 1

        return True

    def is_in_same(self, A, B):
        return self.root(A) == self.root(B)


MOD = 10**9 + 7
INF = 2**31  

from collections import defaultdict, Counter, deque
from operator import itemgetter, xor, add
from itertools import product, permutations, combinations
from bisect import bisect_left, bisect_right  
from functools import reduce
from math import gcd


def lcm(a, b):
    
    g = gcd(a, b)
    return a // g * b


N, M = ints()
uf = UnionFind(N)
for _ in range(M):
    a, b = mina(*ints())
    uf.unite(a, b)





print(-min(uf.parent))

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)

ml = 0
for n in uf.roots():
    ml = max(ml, uf.size(n))

print(ml)

Solution (Python):
class UnionFind:

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


    def unite(self, x, y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return False
        if self.par[x] > self.par[y]:
            x, y = y, x
        self.par[x] += self.par[y]
        self.par[y] = x
        return True


    def root(self, x):
        path = []
        while self.par[x] >= 0:
            path.append(x)
            x = self.par[x]
        for y in path:
            self.par[y] = x
        return x


    def same(self, x, y):
        return self.root(x) == self.root(y)


    def size(self, x):
        return -self.par[self.root(x)]


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

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

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

print(ans)

Solution (Python):
N, M = map(int, input().split())
l = [-1]*N
f = []
cnt = 0
for _ in range(M):
    a, b = map(int, input().split())
    a -= 1
    b -= 1
    if l[a] < 0 and l[b] < 0:
        f.append([a, b])
        l[a] = cnt
        l[b] = cnt
        cnt += 1
    elif l[a] >= 0 and l[b] < 0:
        f[l[a]].append(b)
        l[b] = l[a]
    elif l[b] >= 0 and l[a] < 0:
        f[l[b]].append(a)
        l[a] = l[b]
    elif l[b] != l[a]:
        if len(f[l[a]]) > len(f[l[b]]):
            for i in f[l[b]]:
                l[i] = l[a]
                f[l[a]].append(i)
        else:
            for i in f[l[a]]:
                l[i] = l[b]
                f[l[b]].append(i)
ans = 1
for l in f:
    ans = max(ans, len(l))
print(ans)

Solution (Python):
import collections as cc
I=lambda:list(map(int,input().split()))
mod=10**9+7
n,m=I()
ds=[i for i in range(n+1)]
r=[1]*(n+1)
def find(a):
    while ds[a]!=a:
        a=ds[a]
    return a
def join(a,b):
    x=find(a)
    y=find(b)
    if x!=y:
        ds[x]=ds[y]=min(x,y)
        r[min(x,y)]+=r[max(x,y)]
for i in range(m):
    x,y=I()
    join(x,y)
temp=cc.Counter(ds[1:])
print(max(r))

Solution (Python):
import sys
import math
import itertools
import bisect
from copy import copy
from collections import deque,Counter
from decimal import Decimal
def s(): return input()
def i(): return int(input())
def S(): return input().split()
def I(): return map(int,input().split())
def L(): return list(input().split())
def l(): return list(map(int,input().split()))
def lcm(a,b): return a*b//math.gcd(a,b)
sys.setrecursionlimit(10**9)
INF = 10**9
mod = 10**9+7

class UnionFind:
  def __init__(self,n):
    self.n=[-1]*n
    self.r=[0]*n
  def find_root(self,x):
    if self.n[x]<0:
      return x
    else:
      self.n[x]=self.find_root(self.n[x])
      return self.n[x]
  def unite(self,x,y):
    x=self.find_root(x)
    y=self.find_root(y)
    if x==y:return
    elif self.r[x]>self.r[y]:
      self.n[x]+=self.n[y]
      self.n[y]=x
    else:
      self.n[y]+=self.n[x]
      self.n[x]=y
      if self.r[x]==self.r[y]:
        self.r[y]+=1
  def root_same(self,x,y):
    return self.find_root(x)==self.find_root(y)
  def count(self,x):
    return -self.n[self.find_root(x)]

N,M = I()
u = UnionFind(N)
for i in range(M):
    a,b = I()
    u.unite(a-1,b-1)
ans = 0
for i in range(N):
    ans = max(ans,u.count(i))
print(ans)

Solution (Python):


from collections import deque

class Node():
    def __init__(self, idx):
        self.idx = idx
        self.next_node = []
        self.is_searched = False
    
    def add_node(self, node):
        self.next_node.append(node)

N, M = map(int, input().split())
nodes = {n+1: Node(n+1) for n in range(N)}

for m in range(M):
    A, B = map(int, input().split())
    nodes[A].add_node(nodes[B])
    nodes[B].add_node(nodes[A])


clusters = []
for i in range(N):
    que = deque([nodes[i+1]])
    cluster = []
    while len(que) != 0:
        node = que.pop()
        if not node.is_searched:
            cluster.append(node)
            que.extend(node.next_node)
            node.is_searched = True

    clusters.append(cluster)

print(max([len(cluster) for cluster in clusters]))

Solution (Python):
def connected_components(n, graph):
    components, visited = [], [False] * n

    def dfs(start):
        component, stack = [], [start]

        while stack:
            start = stack[-1]

            if visited[start]:
                stack.pop()
                continue
            else:
                visited[start] = True
                component.append(start)

            for i in graph[start]:
                if not visited[i]:
                    stack.append(i)

        return component

    for i in range(n):
        if not visited[i]:
            components.append(dfs(i))

    return components

n,m=map(int,input().split())
adj=[]
for i in range(n+1):
	adj.append([])
for i in range(m):
	a,b=map(int,input().split())
	adj[a].append(b)
	adj[b].append(a)
mat=connected_components(n+1,adj)
ans=0
for i in mat:
	if(len(i)>ans):
		ans=len(i)
print(ans)

Solution (Python):
if __name__ == "__main__":
    n, m = (int(x) for x in input().split())

    node___neighs = {x: set() for x in range(1, n + 1)}

    for _ in range(m):
        n1,n2 = (int(x) for x in input().split())
        node___neighs[n1].add(n2)
        node___neighs[n2].add(n1)

    node___comp = {}

    curr_comp = 1
    comp___size = {}
    for node in range(1, n+1):
        if node___comp.get(node, False):
            continue
        stack = [node]
        curr_size = 1
        node___comp[node] = curr_comp

        while stack:
            curr_node = stack.pop()
            for neigh in node___neighs[curr_node]:
                if node___comp.get(neigh, False):
                    continue
                node___comp[neigh] = curr_comp
                curr_size += 1
                stack.append(neigh)
            
        comp___size[curr_comp] = curr_size
        curr_comp += 1
    print(max(comp___size.values()))

Solution (Python):
import sys
input = sys.stdin.readline
from collections import defaultdict, deque
N,M = map(int,input().split())
AB = [list(map(int,input().split())) for i in range(M)]

g = defaultdict(set)
for a,b in AB:
    g[a].add(b)
    g[b].add(a)

visited = [False] * (N+1)

ans = 0
for s in range(1,N+1):
    if visited[s]:
        continue
    dq = deque([s])
    cnt = 0
    while dq:
        v = dq.popleft()
        if visited[v]:
            continue
        cnt += 1
        visited[v] = True
        for nv in g[v]:
            if not visited[nv]:
                dq.append(nv)
    ans = max(ans,cnt)

print(ans)