CodeEff/ECCO huggingface dataset:
# Original solution
n,m = list(map(int,input().split()))
branch = set(tuple(map(int,input().split())) for i in range(m))
que = list(range(n))
flag = -1
friend = [{0}]

for a,b in branch:
    for i in range(len(friend)):
        if (a in friend[i]) and (b in friend[i]):
            break
        if (a in friend[i]) or (b in friend[i]):
            friend[i].add(a)
            friend[i].add(b)
            if flag >= 0:
                friend[flag] = friend[flag]|friend[i]
                friend.pop(i)
                break
            flag = i
    if flag == -1:
        friend.append({a,b})
    else: flag = -1

len_friend = list(len(i) for i in friend)
print((max(len_friend)))

# Optimized solution
import sys
sys.setrecursionlimit(10000000)

class Graph:
    def __init__(self,n,side):
        self.side = side
        self.neighbor = [set() for i in range(n+1)]
        self.visited = [False]*(n+1)
        self.group =[0]*n
        self.product()
    def product(self):
        for a,b in self.side:
            self.neighbor[a].add(b)
            self.neighbor[b].add(a)
    def dfs(self,x,a):
        self.group[a] += 1
        self.visited[x] = True
        for i in self.neighbor[x]:
            if self.visited[i]:continue
            self.dfs(i,a)
    def all_dfs(self):
        a = 0
        for i in range(1,n+1):
            if not self.visited[i]:
                self.dfs(i,a)
                a += 1

n,m = list(map(int,input().split()))
side = list(tuple(map(int,input().split()))for i in range(m))
graph1 = Graph(n,side)
graph1.all_dfs()
print((max(graph1.group)))
# Original solution
"""D."""

import sys

#def input() -> str:  # noqa: A001
#    """Input."""
#    return sys.stdin.readline()[:-1]


class UnionFindTree:
    """Union-find."""

    def __init__(self, n: int) -> None:
        """Init."""
        self.n = n
        self.rank = [-1] * n

    def find_root(self, x: int) -> int:
        """Find root."""

        if self.rank[x] < 0:
            return x

        self.rank[x] = self.find_root(self.rank[x])
        return self.rank[x]

    def union(self, x: int, y: int) -> None:
        """Unite two trees."""
        x_root = self.find_root(x)
        y_root = self.find_root(y)

        if x_root == y_root:
            return

        if x_root > y_root:
            x_root, y_root = y_root, x_root

        self.rank[x_root] += self.rank[y_root]
        self.rank[y_root] = x_root

    def get_size(self, x: int) -> int:
        """Get size."""
        return self.rank[self.find_root(x)] * -1

    def is_same(self, x: int, y: int) -> bool:
        """Is same group."""
        return self.find_root(x) == self.find_root(y)


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

tree = UnionFindTree(n)

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

ans = 0

for i in range(n):
    ans = max(ans, tree.get_size(i))

print(ans)


# Optimized solution
"""D."""

import sys


def input() -> str:  # noqa: A001
    """Input."""
    return sys.stdin.readline()[:-1]


class UnionFindTree:
    """Union-find."""

    def __init__(self, n: int) -> None:
        """Init."""
        self.n = n
        self.rank = [-1] * n

    def find_root(self, x: int) -> int:
        """Find root."""

        if self.rank[x] < 0:
            return x

        self.rank[x] = self.find_root(self.rank[x])
        return self.rank[x]

    def union(self, x: int, y: int) -> None:
        """Unite two trees."""
        x_root = self.find_root(x)
        y_root = self.find_root(y)

        if x_root == y_root:
            return

        if x_root > y_root:
            x_root, y_root = y_root, x_root

        self.rank[x_root] += self.rank[y_root]
        self.rank[y_root] = x_root

    def get_size(self, x: int) -> int:
        """Get size."""
        return self.rank[self.find_root(x)] * -1

    def is_same(self, x: int, y: int) -> bool:
        """Is same group."""
        return self.find_root(x) == self.find_root(y)


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

tree = UnionFindTree(n)

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

ans = 0

for i in range(n):
    ans = max(ans, tree.get_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()}

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

uf = UnionFind(N)

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

ans = 0
for r in uf.roots():
    ans = max(ans, uf.size(r))
print(ans)    

# Optimized solution
class UnionFind:

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

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

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

        if x == y:
            return
            
        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x    

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

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

ans = 0
for i in range(N):
    ans = max(ans, -uf.parents[i])
print(ans)
# Original solution
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 size(self, x):
        return -self.par[self.find(x)]
    def same(self, x, y):
        return self.find(x) == self.find(y)
    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]

N, M = list(map(int, input().split()))
UF = UnionFind(N)
for _ in range(M):
  a, b = list(map(int, input().split()))
  UF.union(a-1, b-1)
Roots = UF.roots()
print((max(UF.members(R) for R in Roots)))

# Optimized solution
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 size(self, x):
      if self.par[x]<0:
        return -self.par[x]
      else:
        return 0

N, M = list(map(int, input().split()))
UF = UnionFind(N)
for _ in range(M):
  a, b = list(map(int, input().split()))
  UF.union(a-1, b-1)
result = 0
for i in range(N):
  s = UF.size(i)
  if s>0:
    result = max(result, s)
print(result)
# 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())



f=lambda:list(map(int,input().split()))
N,M=f()
uf=UnionFind(N+1)
for _ in range(M):
    a,b=f()
    uf.union(a,b)
    
print((max([len(i) for i in list(uf.all_group_members().values())])))

# Optimized solution
class UnionFind():
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        self.rnk = [0]*(n+1)

    # ノードxのrootノードを見つける
    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):
        # 入力ノードのrootノードを見つける
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        # すでに同じ木に属していた場合
        if(x == y):
            return 
        # 違う木に属していた場合rnkを見てくっつける方を決める
        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
            # rnkが同じ（深さに差がない場合）は1増やす
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1
    # xとyが同じグループに属するか判断
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    # ノードxが属する木のサイズを返す
    def Count(self, x):
        return -self.root[self.Find_Root(x)]
    

f=lambda:list(map(int,input().split()))
N,M=f()
uf=UnionFind(N+1)
for _ in range(M):
    a,b=f()
    uf.Unite(a,b)
    
print((max([uf.Count(i+1) for i in range(N)])))
# Original solution
import sys
from operator import itemgetter
N,M = list(map(int,input().split()))
A = [0] * M
#B = [0] * M
for i in range(M):
    A[i] = list(map(int,input().split()))
    if A[i][0] > A[i][1]:
        A[i][0],A[i][1] = A[i][1],A[i][0]
A = sorted(A, key = itemgetter(0))        
C = [set()]
if M != 0:
    C[0].add(A[0][0])
    C[0].add(A[0][1])
else:
    print((1))
    sys.exit()
for i in range(1,M):
    for j in range(len(C)):
        if A[i][0] in C[j]:
            C[j].add(A[i][1])
            continue
        elif A[i][1] in C[j]:
            C[j].add(A[i][0])
            continue
        else:
            C.append({A[i][0],A[i][1]})
            continue
ans = 0
for j in range(len(C)):
    if len(C[j]) > ans:
        ans = len(C[j])
print(ans)

# Optimized solution
class UnionFind():
    # 作りたい要素数nで初期化
    # 使用するインスタンス変数の初期化
    def __init__(self, n):
        self.n = n
        # root[x]<0ならそのノードが根かつその値が木の要素数
        # rootノードでその木の要素数を記録する
        self.root = [-1]*(n+1)
        # 木をくっつける時にアンバランスにならないように調整する
        self.rnk = [0]*(n+1)

    # ノードxのrootノードを見つける
    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):
        # 入力ノードのrootノードを見つける
        x = self.Find_Root(x)
        y = self.Find_Root(y)
        # すでに同じ木に属していた場合
        if(x == y):
            return 
        # 違う木に属していた場合rnkを見てくっつける方を決める
        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
            # rnkが同じ（深さに差がない場合）は1増やす
            if(self.rnk[x] == self.rnk[y]):
                self.rnk[y] += 1
    # xとyが同じグループに属するか判断
    def isSameGroup(self, x, y):
        return self.Find_Root(x) == self.Find_Root(y)

    # ノードxが属する木のサイズを返す
    def Count(self, x):
        return -self.root[self.Find_Root(x)]
    
N, M = list(map(int,input().split()))
A = [None] * M
B = [None] * M
for i in range(M):
    A[i], B[i] = list(map(int,input().split()))
uf = UnionFind(N)
for j,h in zip(A,B):
    uf.Unite(j,h)
print((min(uf.root)*(-1)))
# Original solution
a = list(map(int,input().split()))
n = a[0]
m = a[1]

if m != 0:
  ab = [list(map(int, input().split())) for _ in range(m)]
  a, b = [list(i) for i in zip(*ab)]
  
  edge = [[0 for j in range(n)] for i in range(n)]
  for i in range(m):
    edge[a[i]-1][b[i]-1] = 1
    edge[b[i]-1][a[i]-1] = 1

  #print(set_list)

  ans = 1
  for i in range(n):
    aa = sum(edge[i])+1
    ans = max(aa,ans)

  print(ans)
else:
  print((1))

# Optimized solution
n, m = [int(x) for x in input().split()]

if m != 0:
  g = [set() for _ in range(n)]
  valid = [-1] * n
  set_list = []
  for _ in range(m):
    a, b = [int(x) for x in input().split()]
    g[a-1].add(b-1)
    g[b-1].add(a-1)

  j = -1
  for i in range(n):
    if valid[i] == -1:
      set_list.append(set())
      j += 1
      stack = [i]
      while len(stack)!=0:
        v = stack.pop()
        set_list[j].add(v)
        valid[v] = 1
        for i in g[v]:
          if valid[i] == -1:
            stack.append(i)
            set_list[j].add(i)
            valid[i] = 1
  ans = 1
  for i in range(len(set_list)):
    ans = max(len(set_list[i]),ans)

  print(ans)

else:
  print((1))
# Original solution
def solve(N, M, fridens):
    groups = {}
    for x in range(N):
        groups[x] = [x]

    for A, B in friends:
        if B in groups:
            groups[A].append(B)
            del groups[B]

    ans = len(max(list(groups.values()), key=len))
    print(ans)


if __name__ == "__main__":
    N, M = list(map(int, input().split()))
    friends = []
    for _ in range(M):
        AB = sorted([x - 1 for x in map(int, input().split())])
        if AB not in friends:
            friends.append(AB)
    solve(N, M, friends)


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


def find(x):
    while par[x] != 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 = list(map(int, input().split()))
    union(a - 1, b - 1)

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

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


print((max(s)))
# Original solution
import sys
import math
import collections
import bisect
import itertools
import decimal

# import numpy as np

# sys.setrecursionlimit(10 ** 6)
INF = 10 ** 20
MOD = 10 ** 9 + 7
# MOD = 998244353

ni = lambda: int(sys.stdin.readline().rstrip())
ns = lambda: list(map(int, sys.stdin.readline().rstrip().split()))
na = lambda: list(map(int, sys.stdin.readline().rstrip().split()))
na1 = lambda: list([int(x) - 1 for x in sys.stdin.readline().rstrip().split()])


# ===CODE===

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

    uf = UnionFind(n)

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

    ans = 0
    for i in range(n):
        p = min(uf.parents)
        ans = max(ans, -p)

    print(ans)


if __name__ == '__main__':
    main()


# Optimized solution
import sys
import math
import collections
import bisect
import itertools
import decimal

# import numpy as np

# sys.setrecursionlimit(10 ** 6)
INF = 10 ** 20
MOD = 10 ** 9 + 7
# MOD = 998244353

ni = lambda: int(sys.stdin.readline().rstrip())
ns = lambda: list(map(int, sys.stdin.readline().rstrip().split()))
na = lambda: list(map(int, sys.stdin.readline().rstrip().split()))
na1 = lambda: list([int(x) - 1 for x in sys.stdin.readline().rstrip().split()])


# ===CODE===

def main():
    n, m = ns()

    e = [[] for _ in range(n)]

    for _ in range(m):
        a, b = ns()
        a, b = a - 1, b - 1
        e[a].append(b)
        e[b].append(a)

    visited = [False for _ in range(n)]

    ans = 0
    for i in range(n):
        if not visited[i]:
            visited[i] = True
            cnt = 1
            que = collections.deque()
            que.append(i)

            while que:
                q = que.popleft()

                for ei in e[q]:
                    if not visited[ei]:
                        visited[ei] = True
                        cnt += 1
                        que.append(ei)

            ans = max(ans, cnt)
    print(ans)


if __name__ == '__main__':
    main()
# Original solution
N, M = [int(i) for i in input().split()]
Groups = [[i] for i in range(N)]
dsts = [-1 for i in range(N)]
ABs = [[int(i)-1 for i in input().split()] for i in range(M)]
for A, B in ABs:
    dst = min(A, B)
    src = max(A, B)
    # print('A', A, B, dst, src)
    while(dsts[dst] != -1):
        dst = dsts[dst]
    while(dsts[src] != -1):
        src = dsts[src]
    if dst != min(A, B):
        omdst = min(A, B)
        while(dsts[omdst] != dst):
            n_omdst = dsts[omdst]
            dsts[omdst] = dst
            omdst = n_omdst
    if src != max(A, B):
        omsrc = max(A, B)
        while(dsts[omsrc] != src):
            n_omsrc = dsts[omsrc]
            dsts[omsrc] = src
            omsrc = n_omsrc

    if dst == src:
        continue
    dst2 = min(dst, src)
    src2 = max(dst, src)
    dsts[src2] = dst2
    Groups[dst2].extend(Groups[src2])
    Groups[src2] = []
    # print(Groups)
    # print(dsts)
ans = 0
for group in Groups:
    ans = max(ans, len(group))
print(ans)


# Optimized solution
N, M = [int(i) for i in input().split()]
Groups = [1 for i in range(N)]
dsts = [-1 for i in range(N)]
ABs = [[int(i)-1 for i in input().split()] for i in range(M)]
for A, B in ABs:
    dst = min(A, B)
    src = max(A, B)
    # print('A', A, B, dst, src)
    while(dsts[dst] != -1):
        dst = dsts[dst]
    while(dsts[src] != -1):
        src = dsts[src]
    if dst != min(A, B):
        omdst = min(A, B)
        while(dsts[omdst] != dst):
            n_omdst = dsts[omdst]
            dsts[omdst] = dst
            omdst = n_omdst
    if src != max(A, B):
        omsrc = max(A, B)
        while(dsts[omsrc] != src):
            n_omsrc = dsts[omsrc]
            dsts[omsrc] = src
            omsrc = n_omsrc

    if dst == src:
        continue
    dst2 = min(dst, src)
    src2 = max(dst, src)
    dsts[src2] = dst2
    Groups[dst2] += Groups[src2]
    Groups[src2] = 0
    # print(Groups)
    # print(dsts)
print((max(Groups)))
# 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()))
AB = [list(map(int,input().split())) for _ in range(M)]

uf = UnionFind(N)
for i in range(M):
    uf.union(AB[i][0]-1,AB[i][1]-1)
agm = uf.all_group_members()
ufr = uf.roots()
ans = 0
for i in ufr:
    ans = max(ans,len(agm[i]))
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]
    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()))
AB = [list(map(int,input().split())) for _ in range(M)]

uf = UnionFind(N)
for i in range(M):
    uf.union(AB[i][0]-1,AB[i][1]-1)
ufr = uf.roots()
ans = 0
for i in ufr:
    ans = max(ans,uf.size(i))
print(ans)