CodeEff/ECCO huggingface dataset:
# 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

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

uf = UnionFind(n)

ab = [tuple(map(int,input().split())) for _ in range(m)]

for a,b in ab:
    uf.union(a-1,b-1)

ans = -1
for i in uf.parents:
    ans = min(i,ans)
    
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 main():
    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)
    print((-min(list(uf.parents))))
    
main()
# Original solution
class UnionFind: 
    def __init__(self, numV):
        self.pars = list(range(numV))
        self.ranks = [0] * numV
        self.sizes = [1] * numV
    def getRoot(self, x):
        par = self.pars[x]
        if par != x:
            self.pars[x] = par = self.getRoot(par)
        return par
    def merge(self, x, y):
        x, y = self.getRoot(x), self.getRoot(y)
        sx, sy = self.sizes[x], self.sizes[y]
        if x == y: return (0, 0)
        if self.ranks[x] < self.ranks[y]:
            self.pars[x] = y
            self.sizes[y] += sx
        else:
            self.pars[y] = x
            self.sizes[x] += sy
            if self.ranks[x] == self.ranks[y]:
                self.ranks[x] += 1
        return (sx, sy)
    def isSame(self, x, y):
        return self.getRoot(x) == self.getRoot(y)
    def updatePars(self):
        for v in range(len(self.pars)):
            self.getRoot(v)
    def getSize(self, x):
        return self.sizes[self.getRoot(x)]


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

uf = UnionFind(n)
e = [[] for i in range(n)]
for i in range(m):
    a, b = list(map(int,input().split()))
    a -= 1
    b -= 1
    if not b in e[a]:
        uf.merge(a,b)
        e[a].append(b)
        e[b].append(a)

print((max(uf.sizes)))

# Optimized solution
class UnionFind: 
    def __init__(self, numV):
        self.pars = list(range(numV))
        self.ranks = [0] * numV
        self.sizes = [1] * numV
    def getRoot(self, x):
        par = self.pars[x]
        if par != x:
            self.pars[x] = par = self.getRoot(par)
        return par
    def merge(self, x, y):
        x, y = self.getRoot(x), self.getRoot(y)
        sx, sy = self.sizes[x], self.sizes[y]
        if x == y: return (0, 0)
        if self.ranks[x] < self.ranks[y]:
            self.pars[x] = y
            self.sizes[y] += sx
        else:
            self.pars[y] = x
            self.sizes[x] += sy
            if self.ranks[x] == self.ranks[y]:
                self.ranks[x] += 1
        return (sx, sy)
    def isSame(self, x, y):
        return self.getRoot(x) == self.getRoot(y)
    def updatePars(self):
        for v in range(len(self.pars)):
            self.getRoot(v)
    def getSize(self, x):
        return self.sizes[self.getRoot(x)]

import sys
input = sys.stdin.buffer.readline
n, m = list(map(int,input().split()))

uf = UnionFind(n)
e = [[] for i in range(n)]
for i in range(m):
    a, b = list(map(int,input().split()))
    a -= 1
    b -= 1
    if not b in e[a]:
        uf.merge(a,b)

print((max(uf.sizes)))
# 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 i in range(M):
    A, B = list(map(int, input().split()))
    uf.union(A-1, B-1)

max_num = 0
for val in list(uf.all_group_members().values()):
    max_num = max(max_num, len(val))
print(max_num)

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

    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)

# print(uf.roots())

max_num = 0
for root in uf.roots():
    max_num = max(max_num, uf.size(root))
print(max_num)
# Original solution
import sys
from collections import defaultdict
sys.setrecursionlimit(10 + 2 * 10 ** 5)

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

color = [None] * (n + 1)
for i in range(n + 1):
    color[i] = i

def root(x):
    global color

    if color[x] == x:
        return x
    return root(color[x])

memo = [None] * (n + 1)
def memo_root(x):
    global memo
    global color

    if memo[x] is not None:
        return memo[x]

    if color[x] == x:
        memo[x] = x
        return memo[x]

    memo[x] = root(color[x])
    return memo[x]

def unite(x, y):
    rx = root(x)
    ry = root(y)
    if rx == ry:
        return
    color[rx] = ry

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

cnt = defaultdict(int)
for i in range(n):
    cnt[memo_root(i + 1)] += 1
print((max(cnt.values())))

# Optimized solution
import sys
from collections import defaultdict
sys.setrecursionlimit(10 + 2 * 10 ** 5)
 
n, m = list(map(int, input().split()))
 
color = [None] * (n + 1)
for i in range(n + 1):
    color[i] = i
 
def root(x):
    global color
 
    if color[x] == x:
        return x
    color[x] = root(color[x])
    return color[x]
 
def unite(x, y):
    rx = root(x)
    ry = root(y)
    if rx == ry:
        return
    color[rx] = ry
 
for i in range(m):
    a, b = list(map(int, input().split()))
    unite(a, b)
 
cnt = defaultdict(int)
for i in range(n):
    cnt[root(i + 1)] += 1
print((max(cnt.values())))
# Original solution
n, m = list(map(int,input().split()))
par = [-1 for i in range(n + 1)]
par[0] = 0
def find(x):
    if (par[x] < 0):
        return x
    else:
        x = par[x]
        return find(x)
def unit(x, y):
    if (find(x) == find(y)):
        pass
    else:
        x = find(x)
        y = find(y)
        if (x > y):
            x, y = y, x
        s = par[y]
        par[y] = x
        par[x] = par[x] + s

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

par.sort()
print((-par[0]))


# Optimized solution
n, m = list(map(int,input().split()))
lst = [-1 for i in range(n + 1)]
lst[0] = 0
def find(x):
    if(lst[x] < 0):
        return(x)
    else:
        return(find(lst[x]))
def unit(x, y):
    xr = find(x)
    yr = find(y)
    if (xr == yr):
        pass
    else:
        if (xr > yr):
            x, y = y, x
            xr, yr = yr, xr
        lst[xr] = lst[xr] + lst[yr]
        lst[yr] = xr

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

print((-(min(lst))))
# Original solution
import sys
sys.setrecursionlimit(10**9)
n, m = list(map(int, input().split()))

root = [-1]*n

def find(n):
    if root[n] < 0:
        return n
    else:
        return find(root[n])

def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    else:
        root[x] += root[y]
        root[y] = x

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

print((-min(root)))

# Optimized 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)
# Original solution
import sys
sys.setrecursionlimit(10**9)
n, m = list(map(int, input().split()))

root = [-1]*n

def find(n):
    if root[n] < 0:
        return n
    else:
        root[n] = find(root[n])
        return root[n]

def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    else:
        root[x] += root[y]
        root[y] = x

def size(n):
    return -root[find(n)]

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

print((-min(root)))

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

root = [-1]*n

def find(n):
    if root[n] < 0:
        return n
    else:
        root[n] = find(root[n])
        return root[n]

def unite(x, y):
    x = find(x)
    y = find(y)
    if x == y:
        return
    else:
        root[x] += root[y]
        root[y] = x

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

print((-min(root)))
# Original solution
n,m = list(map(int,input().split()))
a = [1]*(n+1)
b = [0]*(n+1)
for i in range(m):
  x,y = list(map(int,input().split()))
  u = x
  while a[u]==0:
    u = b[u]
  v = y
  while a[v]==0:
    v = b[v]
  if u!=v:
    b[v] = u
    a[u] += a[v]
    a[v] = 0
print((max(a)))

# Optimized solution
n,m = list(map(int,input().split()))
a = [1]*(n+1)
b = [0]*(n+1)
for i in range(m):
  x,y = list(map(int,input().split()))
  u = x
  while a[u]==0:
    u = b[u]
  v = y
  while a[v]==0:
    v = b[v]
  if u!=v:
    b[v] = u
    b[y] = u
    b[x] = u
    a[u] += a[v]
    a[v] = 0
print((max(a)))
# 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

    return r(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):
    return -1 * root[r(x)]


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

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


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):
    return -1 * root[r(x)]


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

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

print(ans)
# 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)
AB=[tuple(map(int,input().split())) for _ in range(M)]
x=[uf.union(ab[0]-1,ab[1]-1) for ab in AB]

dic=uf.all_group_members()
print((max([len(d) for d in list(dic.values())])))

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

    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)

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 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, len(uf.members(i)))

print(ans)

# Optimized solution
def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]
#xとyの属する集合の併合
def unite(x,y):
    x = find(x)
    y = find(y)
    
    if x == y:
        return False
    else:
        #sizeの大きいほうがx
        if par[x] > par[y]:
            x,y = y,x
        par[x] += par[y]
        par[y] = x
        return True

#xとyが同じ集合に属するかの判定
def same(x,y):
    return find(x) == find(y)

#xが属する集合の個数
def size(x):
    return -par[find(x)]

#初期化
#根なら-size,子なら親の頂点
n, m = list(map(int, input().split()))
par = [-1]*n

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

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

print(ans)
# 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())

    def max_group_members(self):
        return max([len(self.members(r)) for r in self.roots()])
    
N,M = list(map(int,input().split()))

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

print((uf.max_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 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 max_group_members(self):
        return -min([i for i in self.parents if i<0])
    
N,M = list(map(int,input().split()))

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

print((uf.max_group_members()))
# Original solution
n,m=list(map(int,input().split()))
M=[1 for i in range(n)]
F=[]
for i in range(m):
    a,b=list(map(int,input().split()))
    a,b=min(a,b),max(a,b)
    if [a,b] not in F:
        F.append([a,b])
        M[a-1]+=1
print((max(M)))


# Optimized solution
class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n
 
    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 find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]
 
    def size(self, x):
        return -self.parents[self.find(x)]

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