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 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(uf.group_count()):
    ans = max(ans, uf.size(i))

print(ans)

Solution (Python):
import collections
n, m = map(int, input().split())
par = [i for i in range(n)]

s = list()
"""

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


def find(x):

    while par[x] != x:
        tmp = par[x]
        par[x] = par[par[x]]
        x = par[x]

    return x


def union(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return 0
    else:
        par[x] = y



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


for k in range(n):
    s.append(find(k))

c = collections.Counter(s)
print(max(c.values()))

Solution (Python):
import collections
n, m = map(int, input().split())
par = list(range(2 * n))





def find(x):

    while par[x] != x:
        tmp = par[x]
        par[x] = par[par[x]]
        x = par[x]

    return x


def union(x, y):
    x1 = find(x)
    y1 = find(y)
    if x1 != y1:
        par[x1] = y1



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

s = [0 for i in range(n + 5)]


for k in range(n):
    s[find(k)] += 1

print(max(s))

Solution (Python):
N,M=map(int,input().split())
par=[i for i in range(N)]
size=[1 for i in range(N)]
def find(x):
  if par[x]==x:
    return x
  else:
    par[x]=find(par[x])
    return par[x]
def union(a,b):
  x=find(a)
  y=find(b)
  if x!=y:
    if size[x]<size[y]:
      par[x]=par[y]
      size[y]+=size[x]
    else: 
      par[y]=par[x]
      size[x]+=size[y]
  else:
    return  

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

Solution (Python):
N, M = map(int, input().split())
path = [set() for i in range(N)]
for i in range(M):
    a, b = map(int, input().split())
    path[a-1].add(b-1)
    path[b-1].add(a-1)
visited = [0] * N

ans = 1
for u in range(N):
    if visited[u] == 1:
        continue
    curr = 1
    visited[u] = 1
    next_u = path[u]
    while next_u:
        v = next_u.pop()
        if visited[v] == 1:
            continue
        visited[v] = 1
        curr += 1
        for w in path[v]:
            if visited[w] == 0:
                next_u.add(w)
    ans = max(ans, curr)

print(ans)

Solution (Python):
from collections import deque

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


graph = [set() for _ in range(n+1)]


for i in range(m):
    a, b = map(int, input().split())


    graph[a].add(b)
    graph[b].add(a)


dist = [-1] * (n+1)
dist[0] = 0


d = deque()
ans = 1
for j in range(len(dist)):
    if dist[j] != -1:
        continue
    d.append(j)
    cnt = 0
    while d:
        v = d.popleft()
        for i in graph[v]:
            if dist[i] != -1:
                continue
            dist[i] = dist[v] + 1
            d.append(i)
            cnt = cnt + 1
    ans = max(ans,cnt)

print(ans)

Solution (Python):
from collections import defaultdict

def main():
    N, M = map(int, input().split())
    g = defaultdict(set)

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

    def dfs(u, visited: set):
        stack = [u]
        visited.add(u)
        while stack:
            u = stack.pop()
            for v in g[u]:
                if v not in visited:
                    stack.append(v)
                    visited.add(v)

    count = dict()       
    for u in range(N):
        if u in count:
            continue
        visited = set()
        dfs(u, visited)
        
        count[u] = len(visited)
        for v in visited:
            count[v] = len(visited)

    print(max(count.values()))


if __name__ == '__main__':
    import sys
    sys.setrecursionlimit(10000)
    main()

Solution (Python):
class UnionFind(object):

    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(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 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 is_same(self, x, y):
        return self.find(x) == self.find(y)

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


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 = max(uf.get_size(i) for i in range(N))
    print(ans)


if __name__ == '__main__':
    main()

Solution (Python):
import sys


class UnionFind():
    def __init__(self, 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


N, M = map(int, input().split())
info = [tuple(map(int, s.split())) for s in sys.stdin.readlines()]

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

ans = min(uf.parents)

print(-ans)

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

def main():
    N, M = map(int, input().split())
    A = [0] * M
    B = [0] * M
    for i in range(M):
        A[i], B[i] = map(int, input().split())

    uf = UnionFind(N + 1)
    for i in range(M):
        uf.union(A[i], B[i])

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

if __name__ == '__main__':
    main()

Solution (Python):
'''
	We can show that if u and v belong to the same connected component, then they are friends w/ each other
	So everyone in a given connected component is friends with one another
	So everyone in a given connected component must be separated into different groups

	If we have a CC of with sz nodes in it, then we need at least sz different groups

	So, the minimum number of groups needed is max sz(CC)
'''
import sys
sys.setrecursionlimit(2*10**5+5)

n, m = map(int,input().split())
adj = [[] for u in range(n+1)]
for i in range(m):
	u, v = map(int,input().split())
	adj[u].append(v)
	adj[v].append(u)

vis = [False for u in range(n+1)]
def dfs(u):
	if vis[u]:
		return 0
	vis[u] = True

	sz = 1
	for v in adj[u]:
		sz += dfs(v)
	return sz

CCs = []
for u in range(1,n+1):
	if not vis[u]:
		CCs.append(dfs(u))

print(max(CCs))

Solution (Python):
'''
	We can show that if u and v belong to the same connected component, then they are friends w/ each other
	So everyone in a given connected component is friends with one another
	So everyone in a given connected component must be separated into different groups

	If we have a CC of with sz nodes in it, then we need at least sz different groups

	So, the minimum number of groups needed is max sz(CC)
'''
import sys
sys.setrecursionlimit(4*10**5)

n, m = map(int,input().split())
adj = [[] for u in range(n+1)]
for i in range(m):
	u, v = map(int,input().split())
	adj[u].append(v)
	adj[v].append(u)

vis = [False for u in range(n+1)]
def dfs(u):
	if vis[u]:
		return 0
	vis[u] = True

	sz = 1
	for v in adj[u]:
		sz += dfs(v)
	return sz

CCs = []
for u in range(1,n+1):
	if not vis[u]:
		CCs.append(dfs(u))

print(max(CCs))

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 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_list = [list() for i in range(n)]
        for i in range(n):
          return_list[self.find(i)].append(i)
        return return_list

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


uf = UnionFind(n)
ans = 0

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

for i in uf.all_group_members():
    ans = max(ans, len(i))

print(ans)

Solution (Python):
class UnionFind(object):
    def __init__(self, n=1):
        self.par = [i for i in range(n)]
        self.rank = [0 for _ in range(n)]
        self.size = [1 for _ in range(n)]
    def find(self, x):
        """
        x が属するグループを探索して親を出す。
        """
        if self.par[x] == x:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]
    def union(self, x, y):
        """
        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 is_same(self, x, y):
        """
        x と y が同じグループか否か
        """
        return self.find(x) == self.find(y)
    def get_size(self, x):
        """
        x が属するグループの要素数
        """
        x = self.find(x)
        return self.size[x]



N,M = map(int,input().split())
A = []; B = []
for i in range(M):
  a,b = map(int,input().split())
  a-=1;b-=1 
  A.append(a);B.append(b)

uf = UnionFind(N)
for i in range(M):
  uf.union(A[i],B[i])

ans = 0
for x in range(N):
  temp = uf.get_size(x)
  ans = max(ans,temp)
print(ans)

Solution (Python):

def input_one_number():
    return int(input())


def input_multiple_number():
    return map(int, input().split())


def input_multiple_number_as_list():
    return list(map(int, input().split()))


n,m = input_multiple_number()


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

    
    def isSame(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 getNumGroup(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())

re = UnionFind(n)

for _ in range(m):
	a,b = input_multiple_number()
	re.union(a-1,b-1)

mmax = 0
for nood in re.roots():
	g = re.getGroupSize(nood)
	if mmax < g:
		mmax = g
print(mmax)

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

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

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

    def size(self):
        return -1 * min(self.par)


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)               

print(uf.size())

Solution (Python):
N,M = [int(i) for i in input().split()]
A = list(range(N+1))
for _ in range(M):
  a,b = [int(i) for i in input().split()]
  while A[a] != a:
    a = A[a]
  while A[b] != b:
    b = A[b]
  a,b = [max(a,b),min(a,b)]
  A[a] = b
for i in range(N+1):
  n = A[i]
  while n != A[n]:
    n = A[n]
  A[i] = n
L = [0]*(N+1)
for a in A:
  L[a] += 1
print(max(L))

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 uf.roots():
  ans = max(ans, uf.size(i))
print(ans)

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

if M == 0:
    print(1)
    exit()

group_list = []
group_index = [0] * N

for _ in range(M):
    a, b = map(int, input().split())
    if group_index[a-1] == 0 and group_index[b-1] == 0:
        group_index[a-1] = len(group_list) + 1
        group_index[b-1] = len(group_list) + 1
        group_list.append(set([a, b]))

    elif group_index[a-1] == 0:
        group_index[a-1] = group_index[b-1]
        group_list[group_index[b-1] - 1].add(a)

    elif group_index[b-1] == 0:
        group_index[b-1] = group_index[a-1]
        group_list[group_index[a-1] - 1].add(b)

    elif group_index[a-1] != group_index[b-1]:
        if len(group_list[group_index[a-1] - 1]) > len(group_list[group_index[b-1] - 1]):
            group_id_b = group_index[b-1] - 1
            for p in group_list[group_id_b]:
                group_index[p-1] = group_index[a-1]
                group_list[group_index[a-1] - 1].add(p)
            group_list[group_id_b] = set()
        else:
            group_id_a = group_index[a-1] - 1
            for p in group_list[group_id_a]:
                group_index[p-1] = group_index[b-1]
                group_list[group_index[b-1] - 1].add(p)
            group_list[group_id_a] = set()

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

Solution (Python):
import sys
class UnionFind():
    def __init__(self, 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


N, M = map(int, input().split())
info = [tuple(map(int, s.split())) for s in sys.stdin.readlines()]


uf = UnionFind(N)

for a, b in info:
    a -= 1; b -= 1
    uf.union(a, b)

ans = min(uf.parents)

print(-ans)

Solution (Python):
import sys
def input(): return sys.stdin.readline().rstrip()
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,y=self.find(x),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 main():
    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)
    uf_lis = uf.parents
    ans = 0
    for p in uf_lis:
        if p < 0:
            ans = max(ans, -p)
    print(ans)


if __name__=='__main__':
    main()

Solution (Python):
import sys
def input(): return sys.stdin.readline().rstrip()
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,y=self.find(x),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 all_group_members(self):
        
        return {r: self.members(r) for r in self.roots()}
    def all_group_members_list(self):
        
        
        return list(self.all_group_members().values())
def main():
    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)
    uf_lis = uf.parents
    ans = 0
    for p in uf_lis:
        if p < 0:
            ans = max(ans, -p)
    print(ans)


if __name__=='__main__':
    main()

Solution (Python):
'''
	We can show that if u and v belong to the same connected component, then they are friends w/ each other
	So everyone in a given connected component is friends with one another
	So everyone in a given connected component must be separated into different groups

	If we have a CC of with sz nodes in it, then we need at least sz different groups

	So, the minimum number of groups needed is max sz(CC)
'''
n, m = map(int,input().split())
adj = [[] for u in range(n+1)]
for i in range(m):
	u, v = map(int,input().split())
	adj[u].append(v)
	adj[v].append(u)

vis = [False for u in range(n+1)]
def bfs(s):
	sz = 0
	queue = [s]
	ptr = 0
	
	while ptr < len(queue):
		u = queue[ptr]
		if not vis[u]:
			vis[u] = True
			sz += 1
			for v in adj[u]:
				queue.append(v) 
		ptr += 1

	return sz

CCs = []
for u in range(1,n+1):
	if not vis[u]:
		CCs.append(bfs(u))

print(max(CCs))

Solution (Python):





import math
import fractions
import sys
import bisect
import heapq  
import collections
from collections import Counter
from collections import deque
import pprint
import itertools

"""nを素因数分解"""
"""2以上の整数n => [[素因数, 指数], ...]の2次元リスト"""

def factorization(n):
    arr = []
    temp = n
    if n == 1:
        return arr

    for i in range(2, int(-(-n ** 0.5 // 1)) + 1):
        if temp % i == 0:
            cnt = 0
            while temp % i == 0:
                cnt += 1
                temp //= i
            arr.append([i, cnt])

    if temp != 1:
        arr.append([temp, 1])

    if arr == []:
        arr.append([n, 1])

    return arr



def power(a, n, mod):
    x = 1
    while n:
        if n & 1:
            x *= a % mod
        n >>= 1
        a *= a % mod
    return x % mod



def kaijo(n, l, mod):
    if n == 0:
        return 1
    a = n
    tmp = n - 1
    while (tmp >= l):
        a = a * tmp % mod
        tmp -= 1
    return a


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 make_divisors(n):
    divisors = []
    for i in range(1, int(n**0.5)+1):
        if n % i == 0:
            divisors.append(i)
            if i != n // i:
                divisors.append(n//i)

    divisors.sort()
    return divisors

inf = 10 ** 18
mod = 10 ** 9 + 7

_INPUT = """\
5 3
1 2
3 4
5 1
"""

def main(*, input=input):
    sr = lambda: input()
    ir = lambda: int(sr())
    lr = lambda: list(map(int, sr().split()))

    n,m = lr()
    uf = UnionFind(n)
    for i in range(m):
        a,b = lr()
        a-=1
        b-=1
        uf.union(a,b)
    ans = min(uf.parents)
    print(-ans)

if __name__ == "__main__":
    import io, sys

    

    main()

Solution (Python):
from sys import stdin
from collections import defaultdict
from heapq import *

class UnionFind:

    def __init__(self, n):
        self.n = n
        self.par = [i for i in range(n)]
        self.height = [0] * n
        self.size = [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 getsize(self, x):
        return self.size[self.find(x)]

    def unite(self, x, y):
        x, y = self.find(x), self.find(y)
        if x == y:
            return
        if self.height[x] < self.height[y]:
            self.par[x] = y
            self.size[y] += self.size[x]
        else:
            self.par[y] = self.par[x]
            self.size[x] += self.size[y]
            if self.height[x] == self.height[x]:
                self.height[x] += 1

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

N, M = map(int, input().split())
uf = UnionFind(N+1)
for i in range(M):
    a, b = map(int, input().split())
    uf.unite(a, b)
ans = 0
for i in range(N):
    ans = max(ans, uf.getsize(i+1))
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-1] < 0:
            return x
        else:
            self.parents[x-1] = self.find(self.parents[x-1])
            return self.parents[x-1]
    
    
    def union(self, x, y):
        x = self.find(x) 
        y = self.find(y) 

        if x == y: return
        else:
            
            if self.parents[x-1] > self.parents[y-1]:
                x, y = y, x
            self.parents[x-1] += self.parents[y-1]
            self.parents[y-1] = x 

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

N, M = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
    A,B = map(int, input().split())
    uf.union(A,B)
parents = uf.roots()
ans = 0
for p in parents:
    ans = max(ans, uf.size(p))
print(ans)

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


rooting = [[] for _ in range(N+1)]

for _ in range(M):
    A, B = map(int, input().split())
    rooting[A].append(B)
    rooting[B].append(A)


max_group_num = 1


visited = [0 for _ in range(N+1)]


for i in range(1, N+1):
    if  visited[i] == 1:
        continue
    visited[i] = 1
    queue = [i]
    group_num = 1

    while not queue == []:
        h = queue.pop(0)
        for n in rooting[h]:
            if visited[n] != 1:
                queue.append(n)
                group_num += 1
                visited[n] = 1

    max_group_num = max(max_group_num, group_num)

print(max_group_num)

Solution (Python):
import numpy as np

class UnionFind:
    def __init__(self, sz: int):
        self._par: np.array = np.full(sz + 1, -1)

    def root(self, a: int):
        if self._par[a] < 0:
            return a
        self._par[a] = self.root(self._par[a])
        return self._par[a]
    
    def size(self, a: int):
        return -self._par[self.root(a)]
    
    def unite(self, a, b):
        a = self.root(a)
        b = self.root(b)
        if a != b:
            if self.size(a) < self.size(b):
                a, b = b, a
            self._par[a] += self._par[b]
            self._par[b] = a
    
if __name__ == '__main__':
    N, M = map(int, input().split())
    uf = UnionFind(N + 1)
    for i in range(M):
        a, b = map(int, input().split())
        uf.unite(a, b)
    ans = 1
    for i in range(1, N + 1):
        ans = max(ans, uf.size(i))
    print(ans)

Solution (Python):
class UnionFind:
    def __init__(self, sz: int):
        self._par: list[int] = [-1] * sz

    def root(self, a: int):
        if self._par[a] < 0:
            return a
        self._par[a] = self.root(self._par[a])
        return self._par[a]
    
    def size(self, a: int):
        return -self._par[self.root(a)]
    
    def unite(self, a, b):
        a = self.root(a)
        b = self.root(b)
        if a != b:
            if self.size(a) < self.size(b):
                a, b = b, a
            self._par[a] += self._par[b]
            self._par[b] = a
    
if __name__ == '__main__':
    N, M = map(int, input().split())
    uf = UnionFind(N + 1)
    for i in range(M):
        a, b = map(int, input().split())
        uf.unite(a, b)
    ans = 1
    for i in range(1, N + 1):
        ans = max(ans, uf.size(i))
    print(ans)