CodeEff/ECCO huggingface dataset:
# Original solution
N,M = list(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 {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())

uf = UnionFind(N)

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

group = list(uf.all_group_members().values())
ans = 0
for i in range(len(group)):
    ans = max(ans,len(group[i]))
print(ans)

# Optimized solution
N,M = list(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 {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())

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)
# Original solution
# 連結成分に分解、異なる連結成分から一人ずつ集めたグループが１セット。
# これを全ての連結成分が空になるまで繰り返す。
# 全ての連結成分が空になる <===> 連結成分の最大の要素数回この操作を繰り返せば良い。
# Union FInd が一番適してそう。
class UnionFind():
    
    def __init__(self,N):
        self.N = N
        self.par = [-1]*N
    
    def find(self,x):
        if self.par[x]<0: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:
            return 
        
        if self.par[x]>self.par[y]:
            x,y = y,x
        
        self.par[x] += self.par[y]
        self.par[y] = x
    
    def members(self,x):
        root = self.find(x)
        return len([i for i in range(self.N) if self.find(i)==root])

    def roots(self):
        return [i for i,x in enumerate(self.par) if x < 0]
    
    def calc_max_mem(self):
        root = self.roots()
        nums = [self.members(r) for r in root]
        return max(nums)


N,M=list(map(int,input().split()))
uf = UnionFind(N)
for _ in range(M):
    a,b = list(map(int,input().split()))
    a -= 1;b -= 1
    uf.union(a,b)
print((uf.calc_max_mem()))

# Optimized solution
# 連結成分に分解、異なる連結成分から一人ずつ集めたグループが１セット。
# これを全ての連結成分が空になるまで繰り返す。
# 全ての連結成分が空になる <===> 連結成分の最大の要素数回この操作を繰り返せば良い。
# Union FInd が一番適してそう。
class UnionFind():
    
    def __init__(self,N):
        self.N = N
        self.par = [-1]*N
    
    def find(self,x):
        if self.par[x]<0: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:
            return 
        
        if self.par[x]>self.par[y]:
            x,y = y,x
        
        self.par[x] += self.par[y]
        self.par[y] = x
    

N,M=list(map(int,input().split()))
uf = UnionFind(N)
for _ in range(M):
    a,b = list(map(int,input().split()))
    a -= 1;b -= 1
    uf.union(a,b)
print((-min(uf.par)))
# Original solution
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 group_members(self):
        return [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+1)
for _ in range(m):
    x, y = list(map(int, input().split()))
    uf.unite(x, y)

print((max([len(g) for g in uf.group_members()])))

# Optimized solution
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 group_members(self):
        return [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+1)
for _ in range(m):
    x, y = list(map(int, input().split()))
    uf.unite(x, y)

ans = 0
for i in range(n+1):
    if ans < uf.size(i):
        ans = uf.size(i)
print(ans)
# Original solution
from collections import deque

def main():
    n, m = list(map(int, input().split(" ")))
    v_set = [set([]) for _ in range(n)]
    for _ in range(m):
        a, b = list(map(int, input().split(" ")))
        v_set[a-1].add(b-1)
        v_set[b-1].add(a-1)

    max_num = 0
    seen = [0]*n
    for ni in range(n):
        if seen[ni]:
            continue
        checked = [0]*n
        stack = deque([ni])
        checked[ni] = 1
        while stack:
            cur = stack.pop()
            seen[cur]+=1
            for next_i in v_set[cur]:
                if seen[next_i] or checked[next_i]:
                    continue
                stack.append(next_i)
                checked[next_i] = 1
        max_num = max(max_num, sum(checked))

    print(max_num)

if __name__=="__main__":
    main()


# Optimized solution
from collections import deque

def main():
    n, m = list(map(int, input().split(" ")))
    v_set = [set([]) for _ in range(n)]
    for _ in range(m):
        a, b = list(map(int, input().split(" ")))
        v_set[a-1].add(b-1)
        v_set[b-1].add(a-1)

    max_num = 0
    checked = [0]*n
    for ni in range(n):
        if checked[ni]:
            continue
        stack = deque([ni])
        checked[ni] = 1
        f = 1
        while stack:
            cur = stack.pop()
            for next_i in v_set[cur]:
                if checked[next_i]:
                    continue
                stack.append(next_i)
                checked[next_i] = 1
                f+=1
        max_num = max(max_num, f)

    print(max_num)

if __name__=="__main__":
    main()
# Original solution
from collections import deque

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

def dfs(node):
    while len(todo) > 0:
        node = todo.pop()
        if tf[node] == 0:
            tf[node] = 1
            seen.add(node)
            for nextnode in graph[node]:
                todo.append(nextnode)

todo = deque()
done = set()
for i in range(1,n+1):
    if i in done:
        continue
    else:
        todo.append(i)
        tf = [0 for _ in range(n+1)]
        seen = set()
        dfs(i)
        ans = max(ans,len(seen))
        done |= seen
print(ans)

# Optimized solution
from collections import deque

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

def dfs(node):
    while len(todo) > 0:
        node = todo.pop()
        if tf[node] == 0:
            tf[node] = 1
            seen.add(node)
            for nextnode in graph[node]:
                todo.append(nextnode)

todo = deque()
done = set()
tf = [0 for _ in range(n+1)]
for i in range(1,n+1):
    if i in done:
        continue
    else:
        todo.append(i)
        seen = set()
        dfs(i)
        #print(i,seen)
        ans = max(ans,len(seen))
        done |= seen
print(ans)
# Original solution
n, m = list(map(int, input().split()))


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parent = [int(x) for x in range(n)]
        self.tree_size = [1 for _ in range(n)]

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

        if self.same(x_root, y_root):
            return

        if self.size(x_root) >= self.size(y_root):
            self.parent[y_root] = x_root
            self.tree_size[x_root] += self.tree_size[y_root]
        else:
            self.parent[x_root] = y_root
            self.tree_size[y_root] += self.tree_size[x_root]

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

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

    def same(self, x, y):
        if x == y:
            return True
        else:
            return False


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

# print([uf.size(i) for i in range(n)])
print((max([uf.size(i) for i in range(n)])))


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


class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parent = [int(x) for x in range(n)]
        self.tree_size = [1 for _ in range(n)]

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

        if self.same(x_root, y_root):
            return

        if self.size(x_root) >= self.size(y_root):
            self.parent[y_root] = x_root
            self.tree_size[x_root] += self.tree_size[y_root]
        else:
            self.parent[x_root] = y_root
            self.tree_size[y_root] += self.tree_size[x_root]

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

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

    def same(self, x, y):
        if self.find(x) == self.find(y):
            return True
        else:
            return False


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

# print([uf.size(i) for i in range(n)])
print((max([uf.size(i) for i in range(n)])))
# Original solution
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 _ in range(M):
    a,b=list(map(int,input().split()))
    a-=1
    b-=1
    uf.union(a,b)

L=set(uf.roots())
Ls=uf.all_group_members()
ans=0
for k in L:
    ans=max(ans,len(Ls[k]))
print(ans)

# Optimized solution
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]


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

L=set(uf.roots())
ans=0
for k in L:
    ans=max(ans,uf.size(k))
print(ans)
# Original solution
N, M = list(map(int, input().split()))

par = list(range(N))
rank = [1]*N
size = [1]*N

def find(x):
  if par[x] == x:
    return x
  else:
    return find(par[x])
  
def unite(x,y):
  x = find(x)
  y = find(y)
  
  if x == y:
    return
  if rank[x]<rank[y]:
    par[x]=y
    size[y]+= size[x]
  else:
    par[y] = x
    size[x] += size[y]
    if rank[x]==rank[y]:
      rank[x]+=1
    
for i in range(M):
  a,b = [int(i)-1 for i in input().split()]
  unite(a,b)
  
print((max(size)))

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

par = list(range(N))
rank = [1]*N
size = [1]*N

def find(x):
  if par[x] == x:
    return x
  else:
    return find(par[x])
  
def unite(x,y):
  x = find(x)
  y = find(y)
  
  if x == y:
    return
  if rank[x]<rank[y]:
    x,y = y,x
  par[y] = x
  size[x] += size[y]
  if rank[x]==rank[y]:
    rank[x]+=1
    
for i in range(M):
  a,b = [int(i)-1 for i in input().split()]
  unite(a,b)
  
print((max(size)))
# Original solution
N, M = list(map(int, input().split()))

friend_list = []
for i in range(M):
  pair = list(map(int, input().split()))
  friend_list.append(set(pair))

group_num_people = []
for i, group in enumerate(friend_list):
  group_list = [group]
  for j, target in enumerate(friend_list):
    if i == j:
      continue
    else:
      if len(group.intersection(target)) >= 1:
        group_list.append(target)
  group_num_people.append(len(set().union(*group_list)))


if M == 0:
  print((1))
else:
  print((max(group_num_people)))

# Optimized solution
#!/usr/bin/env python
# -*- coding: utf-8 -*-


class UnionFind():
    """ UnionFindはグループの分割はできないことに注意 """
    def __init__(self, n):
        """
            n: 要素数
            parents: 親を示す、-1の場合、自身の親がいない(頂点)であることを示す
        """
        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と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 most_depth_root(self):
        return -min(self.parents)


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

union_find = UnionFind(N)
for i in range(M):
    x, y = list(map(int, input().split()))
    x -= 1
    y -= 1
    union_find.union(x, y)

print((union_find.most_depth_root()))
# Original solution
from collections import *
N,M=list(map(int,input().split()))
AB=[list(map(int,input().split())) for i in range(M)]

lst=[[] for i in range(N+1)]

for a,b in AB:
    lst[a].append(b)
    lst[b].append(a)



used=set(list(range(1,N+1)))
value=-10**18
while used:
    a=used.pop()
    stack=[a]

    visited={a}
    while stack:
        a=stack.pop()
        for p in lst[a]:
            if not p in visited:
                visited.add(p)
                stack.append(p)
    value=max(len(visited),value)
print(value)


# Optimized solution
from collections import *
N,M=list(map(int,input().split()))
AB=[list(map(int,input().split())) for i in range(M)]

lst=[[] for i in range(N+1)]

for a,b in AB:
    lst[a].append(b)
    lst[b].append(a)



used=set(list(range(1,N+1)))
value=-10**18
while used:
    a=used.pop()
    stack=[a]

    visited={a}
    while stack:
        a=stack.pop()
        for p in lst[a]:
            if p in used:
                used.remove(p)
            if not p in visited:
                visited.add(p)
                stack.append(p)
    value=max(len(visited),value)
print(value)
# Original solution
import sys
n, m = list(map(int, input().split()))
input = sys.stdin.readline
sys.setrecursionlimit(10**7)


class UnionFind:
    def __init__(self, n):
        self.p = [-1]*n
        self.r = [1]*n

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

    def union(self, x, y):
        rx, ry = self.find(x), self.find(y)
        if rx != ry:
            if self.r[rx] > self.r[ry]:
                rx, ry = ry, rx
            if self.r[rx] == self.r[ry]:
                self.r[ry] += 1
            self.p[ry] += self.p[rx]
            self.p[rx] = ry

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

    def count_members(self, x):
        return -self.p[self.find(x)]

    def count_roots(self):
        return sum(p < 0 for p in self.p)


uf = UnionFind(n)
for _ in range(m):
    a, b = [int(x)-1 for x in input().split()]
    uf.union(a, b)

ans = 0
for i in range(n):
    x = uf.count_members(i)
    if ans < x:
        ans = x
print(ans)


# Optimized solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
n, m = list(map(int, input().split()))


class UnionFind:
    def __init__(self, n):
        self.p = [-1]*n
        self.r = [1]*n

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

    def union(self, x, y):
        rx, ry = self.find(x), self.find(y)
        if rx != ry:
            if self.r[rx] > self.r[ry]:
                rx, ry = ry, rx
            if self.r[rx] == self.r[ry]:
                self.r[ry] += 1
            self.p[ry] += self.p[rx]
            self.p[rx] = ry

    def count_members(self, x):
        return -self.p[self.find(x)]


uf = UnionFind(n)
for _ in range(m):
    a, b = [int(x)-1 for x in input().split()]
    uf.union(a, b)

ans = 0
for i in range(n):
    x = uf.count_members(i)
    if ans < x:
        ans = x
print(ans)
# Original solution
import sys
sys.setrecursionlimit(10**9)
n,m=list(map(int,input().split()))
root=[-1]*n
def r(x):
    if root[x]<0:
        return x
    else:
        root[x]=r(root[x])
        return root[x]
def unite(x,y):
    x=r(x)
    y=r(y)
    if x==y:
        return
    root[x]+=root[y]
    root[y]=x
def size(x):
    x=r(x)
    return -root[x]
for i in range(m):
    x,y=list(map(int,input().split()))
    x-=1
    y-=1
    unite(x,y)
ans=0
for i in range(n):
    ans=max(ans,size(i))
print(ans)





# Optimized solution
import sys
sys.setrecursionlimit(10**9)
n,m=list(map(int,input().split()))
root=[-1]*(n+1)
def r(x):
    if root[x]<0:
        return x
    else:
        root[x]=r(root[x])
        return root[x]
def unite(x,y):
    x=r(x)
    y=r(y)
    if x==y:
        return
    root[x]+=root[y]
    root[y]=x
def size(x):
    x=r(x)
    return -root[x]
for i in range(m):
    x,y=list(map(int,input().split()))

    unite(x,y)
ans=0
for i in range(n):
    ans=max(ans,size(i+1))
print(ans)
# Original solution
import sys
sys.setrecursionlimit(10**9)
n,m=list(map(int,input().split()))
root=[-1]*(n+1)
def r(x):
    if root[x]<0:
        return x
    else:
        root[x]=r(root[x])
        return root[x]
def unite(x,y):
    x=r(x)
    y=r(y)
    if x==y:
        return
    if x>y:
        x,y=y,x

    root[x]+=root[y]
    root[y]=x
def size(x):
    x=r(x)
    return -root[x]
for i in range(m):
    x,y=list(map(int,input().split()))

    unite(x,y)
ans=0
for i in range(n):
    ans=max(ans,size(i+1))
print(ans)


# Optimized solution
import sys
sys.setrecursionlimit(10**9)
input = sys.stdin.readline
n,m=list(map(int,input().split()))
root=[-1]*(n+1)
def r(x):
    if root[x]<0:
        return x
    else:
        root[x]=r(root[x])
        return root[x]
def unite(x,y):
    x=r(x)
    y=r(y)
    if x==y:
        return
    if x>y:
        x,y=y,x

    root[x]+=root[y]
    root[y]=x
def size(x):
    x=r(x)
    return -root[x]
for i in range(m):
    x,y=list(map(int,input().split()))

    unite(x,y)
ans=0
for i in range(n):
    ans=max(ans,size(i+1))
print(ans)