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-----
5 3
1 2
3 4
5 1

-----Sample Output-----
3

Dividing them into three groups such as \{1,3\}, \{2,4\}, and \{5\} achieves the goal.

Difficulty: MEDIUM

Solutions:
from collections import deque
(N, M) = map(int, input().split())
g = {i: set() for i in range(N)}
v = [-1 for i in range(N)]
for _ in range(M):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	g[a].add(b)
	g[b].add(a)
Q = deque()
ans = 0
for a in g:
	if v[a] == -1:
		v[a] = 1
		ans_tmp = 1
		Q.append(a)
		while len(Q) > 0:
			na = Q.popleft()
			for nb in g[na]:
				if v[nb] == -1:
					v[nb] = 1
					ans_tmp += 1
					Q.append(nb)
		ans = max(ans, ans_tmp)
print(ans)


(n, m) = map(int, input().split())
par = [-1 for _ in range(n)]

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

def union(x, y):
	(rx, ry) = (root(x), root(y))
	if rx == ry:
		pass
	else:
		if par[rx] > par[ry]:
			(rx, ry) = (ry, rx)
		par[rx] += par[ry]
		par[ry] = rx

def size(x):
	return -par[root(x)]
for _ in range(m):
	(a, b) = map(lambda x: int(x) - 1, input().split())
	union(a, b)
ans = 0
for i in range(n):
	ans = max(ans, size(i))
print(ans)


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.parents = [-1] * n
		self.size = [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.size[x] += self.size[y]
		self.size[y] = self.size[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))


(n, m) = map(int, input().split())
r = [[] for i in range(n)]
for i in range(m):
	(x, y) = map(int, input().split())
	r[x - 1].append(y - 1)
	r[y - 1].append(x - 1)
max = 0
mark = []
for i in range(n):
	mark.append('t')
for i in range(n):
	if mark[i] == 't':
		s = 0
		mark[i] = 'f'
		stack = [i]
		while stack:
			x = stack.pop()
			s += 1
			for j in range(len(r[x])):
				nx = r[x][j]
				if mark[nx] == 't':
					mark[nx] = 'f'
					stack.append(nx)
	if max < s:
		max = s
print(max)


from collections import deque
(n, m) = map(int, input().split())
if m == 0:
	print(1)
	exit()
g = [[] for i in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	g[a - 1].append(b - 1)
	g[b - 1].append(a - 1)
v = [-1 for i in range(n)]
ans = []
for i in range(n):
	if v[i] != -1:
		continue
	v[i] = 0
	an = 1
	d = deque([i])
	while len(d):
		x = d.popleft()
		for i in g[x]:
			if v[i] == -1:
				d.append(i)
				v[i] = 1
				an += 1
	ans.append(an)
print(max(ans))


(N, M) = map(int, input().split())
par = [i for i in range(N)]

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

def unite(x, y):
	x = find(x)
	y = find(y)
	if x > y:
		par[x] = y
		find(x)
	else:
		par[y] = x
		find(y)
if M > 0:
	for i in range(M):
		(a, b) = map(int, input().split())
		unite(a - 1, b - 1)
	ans = [0] * N
	Max = 0
	for i in range(N):
		find(i)
	for i in par:
		ans[i] += 1
	for i in ans:
		if i > Max:
			Max = i
	print(Max)
else:
	print(1)


(n, m) = map(int, input().split())
par = [-1] * (n + 1)

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

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

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

def size(x):
	return -par[find(x)]
max_size = 0
for _ in range(m):
	(a, b) = map(int, input().split())
	unite(a, b)
print(-min(par))


(N, M) = (int(d) for d in input().split())
C = [set() for i in range(N + 1)]
for i in range(M):
	(A, B) = (int(d) for d in input().split())
	C[A].update([B])
	C[B].update([A])
seen = set()
G = []
for i in range(1, N + 1):
	if i in seen:
		continue
	G.append(set())
	Q = [i]
	G[-1].update(Q)
	seen.update(Q)
	while len(Q) > 0:
		I = Q.pop(0)
		J = C[I].difference(seen)
		Q += list(J)
		G[-1].update(J)
		seen.update(J)
print(max([len(g) for g in G]))


l = lambda : map(int, input().split())
(n, m) = l()
p = [-1] * n

def r(x):
	if p[x] < 0:
		return x
	p[x] = r(p[x])
	return r(p[x])

def u(x, y):
	(x, y) = (r(x), r(y))
	if x == y:
		return
	p[x] += p[y]
	p[y] = x

def e(x, y):
	return r(x) == r(y)

def s(x):
	return -p[r(x)]
for _ in range(m):
	(a, b) = l()
	u(a - 1, b - 1)
print(-min(p))


(n, m) = map(int, input().split())
ab = []
data = [[] for i in range(n + 1)]
for i in range(m):
	(a, b) = map(int, input().split())
	ab.append([a, b])
	data[a].append(b)
	data[b].append(a)
flag = [0] * (n + 1)
cnt = [0] * (n + 1)
for i in range(1, n + 1):
	if flag[i] == 0:
		cnt[i] += 1
		flag[i] = 1
		que = [i]
		while que:
			h = que.pop()
			for u in data[h]:
				if flag[u] == 0:
					cnt[i] += 1
					flag[u] = 1
					que.append(u)
print(max(cnt))


import sys
sys.setrecursionlimit(10 ** 8)
(n, m) = map(int, input().split())
g = [[] for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	g[a].append(b)
	g[b].append(a)
friends = [0 for _ in range(n)]

def dfs(v):
	global n
	friends[v] = n
	n += 1
	for next_v in g[v]:
		if friends[next_v] == 0:
			dfs(next_v)
for i in range(n):
	if friends[i] == 0:
		n = 1
		dfs(i)
print(max(friends))


from _collections import deque
(n, m) = map(int, input().split())
f = [[] for i in range(n + 1)]
for i in range(m):
	(a, b) = map(int, input().split())
	f[a].append(b)
	f[b].append(a)
g = [0] * (n + 1)
p = [0] * (n + 1)
for i in range(1, n + 1):
	if p[i] == 0:
		p[i] = i
		data = [i]
		data = deque(data)
		while len(data) > 0:
			pos = data.popleft()
			p[pos] = i
			for j in f[pos]:
				if p[j] == 0:
					data.append(j)
for i in range(n):
	g[p[i + 1]] += 1
print(max(g))


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())
A = [0 for _ in range(M)]
B = [0 for _ in range(M)]
for i in range(M):
	(A[i], B[i]) = map(int, input().split())
uf = UnionFind(N)
for i in range(M):
	uf.union(A[i] - 1, B[i] - 1)
ans = 0
for i in range(uf.group_count()):
	ans = max(ans, uf.size(i))
print(ans)


(n, m) = map(int, input().split())
V = [set() for _ in range(n)]
for (a, b) in [[*map(lambda x: int(x) - 1, input().split())] for _ in range(m)]:
	V[a].add(b)
	V[b].add(a)
from collections import deque
G = [-1] * n
for s in range(n):
	dq = deque([s])
	while dq:
		p = dq.popleft()
		if G[p] >= 0:
			continue
		G[p] = s
		for c in V[p]:
			dq.append(c)
C = dict()
for g in G:
	if not g in C:
		C[g] = 0
	C[g] += 1
print(max(C.values()))


from collections import deque
(n, m) = map(int, input().split())
G = [[] for _ in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	G[a - 1].append(b - 1)
	G[b - 1].append(a - 1)
visited = [0] * n

def friends(v):
	stack = deque([v])
	visited[v] = 1
	cnt = 1
	while stack:
		v = stack.popleft()
		for nv in G[v]:
			if visited[nv]:
				continue
			visited[nv] = 1
			stack.append(nv)
			cnt += 1
	return cnt
max_friends = 0
for i in range(n):
	if visited[i]:
		continue
	max_friends = max(max_friends, friends(i))
print(max_friends)


import sys
sys.setrecursionlimit(1000000)
f = lambda : map(int, input().split())
(N, M) = map(int, input().split())
par = [-1] * (N + 1)

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

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	if par[x] > par[y]:
		(x, y) = (y, x)
	par[x] += par[y]
	par[y] = x
	return
for i in range(M):
	(a, b) = map(int, input().split())
	unite(a, b)
print(-min(par[1:]))


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = 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) = 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)


import sys
sys.setrecursionlimit(10 ** 7)
(N, M) = map(int, input().split())
visited = [0] * N
frnds = [[] for i in range(N)]
for _ in range(M):
	(a, b) = map(int, input().split())
	frnds[a - 1].append(b - 1)
	frnds[b - 1].append(a - 1)
for i in range(N):
	frnds[i] = list(set(frnds[i]))

def saiki(num):
	value = 1
	visited[num] = 1
	for f in frnds[num]:
		if visited[f] != 1:
			value += saiki(f)
	return value
ans = 0
for i in range(N):
	if visited[i] != 1:
		ans = max(saiki(i), ans)
print(ans)


(N, M) = map(int, input().split())
ans = 0
V = [[] for i in range(N)]
for i in range(M):
	(a, b) = map(int, input().split())
	V[a - 1] += [b - 1]
	V[b - 1] += [a - 1]
visited = [0] * N
for i in range(N):
	if visited[i] == 0:
		visited[i] = 1
		x = 1
		que = [i]
		while que:
			q = que.pop()
			for v in V[q]:
				if visited[v] == 0:
					que += [v]
					x += 1
					visited[v] = 1
		ans = max(x, ans)
print(ans)


def find(x):
	if par[x] < 0:
		return x
	else:
		tank = []
		while par[x] >= 0:
			tank.append(x)
			x = par[x]
		for elt in tank:
			par[elt] = x
		return x

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

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

def size(x):
	return -par[find(x)]
(N, M) = map(int, input().split())
par = [-1] * N
for _ in range(M):
	(a, b) = map(int, input().split())
	unite(a - 1, b - 1)
print(-min(par))


def root(a):
	if p[a] == a:
		return a
	p[a] = root(p[a])
	return p[a]

def merge(a, b, p, size):
	ra = root(a)
	rb = root(b)
	if ra == rb:
		return
	size[rb] += size[ra]
	p[ra] = rb
(n, m) = list(map(int, input().split()))
size = [1] * n
p = [0] * n
for i in range(n):
	p[i] = i
for i in range(m):
	(a, b) = list(map(int, input().split()))
	a -= 1
	b -= 1
	merge(a, b, p, size)
ans = 0
for x in size:
	ans = max(ans, x)
print(ans)


(n, m) = map(int, input().split())
par = [i for i in range(n + 1)]
size = [1] * (n + 1)

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

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


import collections
import fractions
import itertools
import functools
import bisect
import heapq
import math
import operator
import sys
sys.setrecursionlimit(10 ** 9 + 7)
(N, M) = list(map(int, input().split()))

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

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

def solve():
	group = UnionFind(N)
	for i in range(M):
		(a, b) = [int(x) - 1 for x in input().split()]
		group.union(a, b)
	ans = 0
	for i in range(N):
		ans = max(ans, group.size(i))
	print(ans)
	return 0

def __starting_point():
	solve()
__starting_point()


import sys
input = sys.stdin.readline
(n, m) = list(map(int, input().split()))
N = [[] for _ in range(n)]
V = [0] * n
for _ in range(m):
	(a, b) = list(map(int, input().split()))
	a -= 1
	b -= 1
	N[a].append(b)
	N[b].append(a)
for i in range(n):
	N[i] = list(set(N[i]))
ans = 0
for i in range(n):
	if V[i] == 0:
		cnt = 1
		Q = [i]
		V[i] = 1
		while Q:
			node = Q.pop()
			for child in N[node]:
				if V[child] == 0:
					Q.append(child)
					V[child] = 1
					cnt += 1
		ans = max(ans, cnt)
print(ans)


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 __starting_point():
	(n, m) = map(int, input().split())
	unionfind = UnionFind(n)
	for _ in range(m):
		(a, b) = map(int, input().split())
		unionfind.union(a - 1, b - 1)
	answer = []
	for i in range(n):
		answer.append(unionfind.size(i))
	print(max(answer))
__starting_point()


(n, m) = map(int, input().split())
par = [-1 for i in range(n + 1)]

def root(a):
	if par[a] < 0:
		return a
	else:
		return root(par[a])

def size(a):
	return -par[root(a)]

def connect(a, b):
	a = root(a)
	b = root(b)
	if a == b:
		return False
	if size(a) < size(b):
		(a, b) = (b, a)
	par[a] += par[b]
	par[b] = a
	return True
for i in range(m):
	(a, b) = map(int, input().split())
	connect(a - 1, b - 1)
ans = 0
for i in par:
	if i < 0:
		ans = max(ans, -i)
print(ans)


(N, M) = map(int, input().split())
t = [-1] * N
import sys
sys.setrecursionlimit(10 ** 6)

def find(e):
	if t[e] < 0:
		return e
	else:
		t[e] = find(t[e])
		return t[e]

def unite(a, b):
	a_root = find(a)
	b_root = find(b)
	if a_root == b_root:
		return
	t[a_root] += t[b_root]
	t[b_root] = a_root
for i in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	unite(a, b)

def size(x):
	x = find(x)
	return -t[x]
ans = 0
for i in range(N):
	ans = max(ans, size(i))
print(ans)


(n, m) = 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) = 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))


f = lambda : map(int, input().split())
(n, m) = f()
p = [-1] * n

def root(x):
	while p[x] >= 0:
		x = p[x]
	return x

def unite(x, y):
	(x, y) = (root(x), root(y))
	if x == y:
		return
	if x > y:
		(x, y) = (y, x)
	p[x] += p[y]
	p[y] = x
for i in range(m):
	(a, b) = f()
	unite(a - 1, b - 1)
print(-min(p))


from collections import deque
(n, m) = map(int, input().split())
friend = [set() for i in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	friend[a - 1].add(b - 1)
	friend[b - 1].add(a - 1)
flag = [True for i in range(n)]
max_grupe = 0
for i in range(n):
	if flag[i] == False:
		continue
	num = 0
	queue = deque([i])
	flag[i] = False
	while queue:
		now = queue.popleft()
		num += 1
		for j in friend[now]:
			if flag[j]:
				queue.append(j)
				flag[j] = False
	max_grupe = max(max_grupe, num)
print(max_grupe)


from sys import stdin
input = lambda : stdin.readline().strip()
from math import ceil, sqrt, factorial, gcd
from collections import deque
from bisect import bisect_left, bisect_right
(n, m) = map(int, input().split())
graph = {i: set() for i in range(1, n + 1)}
for i in range(m):
	(a, b) = map(int, input().split())
	graph[a].add(b)
	graph[b].add(a)
v = set()
z = []

def dfs(x):
	st = [x]
	while st:
		x = st.pop()
		if x not in v:
			z[-1] += 1
			for i in graph[x]:
				if i not in v:
					st.append(i)
			v.add(x)
for i in range(1, n + 1):
	if i not in v:
		z.append(0)
		dfs(i)
print(max(z))


class UnionFind:

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

	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

	def size(self, x):
		return -1 * self.parents[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())
(N, M) = map(int, input().split())
uf = UnionFind(N)
for i in range(M):
	(a, b) = map(int, input().split())
	uf.union(a, b)
ans = 0
R = uf.roots()
for r in R:
	ans = max(ans, uf.size(r))
print(ans)


import statistics
(N, M) = list(map(int, input().split()))
A = [0] * M
B = [0] * M
par = [-1] * N

def find(x):
	if par[x] < 0:
		return x
	else:
		tank = []
		while par[x] >= 0:
			tank.append(x)
			x = par[x]
		for elt in tank:
			par[elt] = x
		return x

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return False
	else:
		par[x] += par[y]
		par[y] = x
		return True
for i in range(M):
	(A[i], B[i]) = sorted(map(int, input().split()))
	unite(A[i] - 1, B[i] - 1)
print(min(par) * -1)


(N, M) = map(int, input().split())
p = [-1] * N

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

def union(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	p[y] += p[x]
	p[x] = y
	return

def size(x):
	return -p[p[x]]
for _ in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	union(a, b)
ans = max(map(size, range(N)))
print(ans)


(n, m) = map(int, input().split())
li = [-1] * n

def find(x):
	if li[x] < 0:
		return x
	else:
		li[x] = find(li[x])
		return li[x]

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

def same(x, y):
	return find(x) == find(y)
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	unite(a, b)
ans = 0
for i in range(n):
	ans = max(ans, -li[i])
print(ans)


def find(x):
	if par[x] < 0:
		return x
	else:
		tank = []
		while par[x] >= 0:
			tank.append(x)
			x = par[x]
		for elt in tank:
			par[elt] = x
		return x

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

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

def size(x):
	return -par[find(x)]
(n, m) = map(int, input().split())
par = [-1] * n
ans = 0
for i in range(m):
	(X, Y) = map(int, input().split())
	unite(X - 1, Y - 1)
for i in range(n):
	ans = max(size(i), ans)
print(ans)


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

class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rank = [0] * (n + 1)

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

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return 0
		elif self.rank[x] > self.rank[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
		if self.rank[x] == self.rank[y]:
			self.rank[y] += 1

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

	def size(self, x):
		return -self.root[self.find(x)]
link = UnionFind(n)
for _ in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	link.unite(a, b)
print(-min(link.root))


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

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

def unite(x, y):
	p = find(x)
	q = find(y)
	if p == q:
		return None
	if p > q:
		(p, q) = (q, p)
	par[p] += par[q]
	par[q] = p

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

def size(x):
	return -par[find(x)]
par = [-1 for i in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	unite(a - 1, b - 1)
ans = 0
for i in range(n):
	ans = max(ans, size(i))
print(ans)


(n, m) = map(int, input().split())
l = []
for i in range(m):
	(a, b) = map(int, input().split())
	l.append([a, b])

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)]
uf = UnionFind(n)
for i in range(m):
	uf.union(l[i][0] - 1, l[i][1] - 1)
s = []
for i in range(n):
	s.append(uf.size(i))
print(max(s))


class UnionFind:

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

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

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

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

	def size(self, x):
		return -self.d[self.find(x)]
(n, m) = map(int, input().split())
uf = UnionFind(n)
for _ in range(m):
	(a, b) = map(int, input().split())
	uf.unite(a - 1, b - 1)
ans = 0
for i in range(n):
	ans = max(ans, uf.size(i))
print(ans)


import queue
(n, m) = map(int, input().split())
fri = [[] for i in range(n)]
for i in range(m):
	(ai, bi) = map(int, input().split())
	fri[ai - 1].append(bi - 1)
	fri[bi - 1].append(ai - 1)
seen = [0 for i in range(n)]
ans = 0
for i in range(n):
	if seen[i] == 1:
		continue
	cnt = 1
	q = queue.Queue()
	q.put(i)
	seen[i] = 1
	while not q.empty():
		p = q.get()
		for pnext in fri[p]:
			if seen[pnext] == 0:
				q.put(pnext)
				seen[pnext] = 1
				cnt += 1
	ans = max(ans, cnt)
print(ans)


from collections import Counter
(n, m) = map(int, input().split())
adj = [[] for a in range(n + 1)]
for i in range(m):
	(a, b) = map(int, input().split())
	adj[a].append(b)
	adj[b].append(a)
cc = [None for a in range(n + 1)]
ccid = 0
for u in range(1, n + 1):
	if cc[u] != None:
		continue
	ccid += 1
	queue = [u]
	while len(queue) > 0:
		a = queue.pop()
		if cc[a] == None:
			cc[a] = ccid
			queue.extend(adj[a])
counter = Counter(cc)
print(max(counter.values()))


import sys
sys.setrecursionlimit(1000000)
(n, m) = map(int, input().split())
par = [i for i in range(n)]

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

def union(x, y):
	x = find(x)
	y = find(y)
	if x != y:
		par[x] = y
f = lambda x: int(x) - 1
for i in range(m):
	(x, y) = map(f, input().split())
	union(x, y)
for j in range(n):
	find(j)
from collections import Counter
c = Counter(par)
cv = c.values()
print(max(cv))


import sys
(n, m) = map(int, next(sys.stdin).split())
adj = [[] for _ in range(n)]
for _ in range(m):
	ln = next(sys.stdin)
	(a, b) = map(int, ln.split())
	(a, b) = (a - 1, b - 1)
	adj[a].append(b)
	adj[b].append(a)
ans = 0
vis = [0] * n
for i in range(n):
	if vis[i]:
		continue
	vis[i] = 1
	k = 0
	stk = [i]
	while stk:
		u = stk.pop()
		k += 1
		for v in adj[u]:
			if vis[v]:
				continue
			vis[v] = 1
			stk.append(v)
	ans = max(ans, k)
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(N, M) = map(int, input().split())
tree = [-1] * N

def root(x):
	if tree[x] < 0:
		return x
	else:
		tree[x] = root(tree[x])
		return tree[x]

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

def size(x):
	return -tree[root(x)]
for i in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	unite(a, b)
print(max(map(size, range(N))))


from collections import deque

def bfs(start):
	q = deque([start])
	vis[start] = 1
	res = 1
	while q:
		v = q.popleft()
		for to in g[v]:
			if not vis[to]:
				vis[to] = 1
				q.append(to)
				res += 1
	return res
input = __import__('sys').stdin.readline
(n, m) = map(int, input().split())
g = [[] for _ in range(n + 1)]
vis = [0] * (n + 1)
for _ in range(m):
	(a, b) = map(int, input().split())
	g[a] += (b,)
	g[b] += (a,)
ans = 0
for i in range(1, n + 1):
	if not vis[i]:
		ans = max(ans, bfs(i))
print(ans)


(n, m) = map(int, input().split())
g = [[] for _ in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	g[a - 1].append(b - 1)
	g[b - 1].append(a - 1)
visited = [-1] * n
lst = []
k = 0
for i in range(n):
	if visited[i] != -1:
		continue
	visited[i] = k
	temp = [i]
	cnt = 1
	while temp:
		p = temp.pop()
		for q in g[p]:
			if visited[q] != -1:
				continue
			visited[q] = k
			temp.append(q)
			cnt += 1
	lst.append(cnt)
print(max(lst))


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


(n, m) = map(int, input().split())
p = []
sz = []

def find(x):
	if p[x] == x:
		return x
	p[x] = find(p[x])
	return p[x]

def join(u, v):
	u = find(u)
	v = find(v)
	if u == v:
		return
	if sz[u] > sz[v]:
		u ^= v
		v ^= u
		u ^= v
	sz[v] += sz[u]
	p[u] = v
for i in range(n + 1):
	p.append(i)
	sz.append(1)
for i in range(m):
	(a, b) = map(int, input().split())
	join(a, b)
mx = 0
for i in range(1, n + 1):
	if p[i] != i:
		continue
	mx = max(mx, sz[i])
print(mx)


(n, m) = 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) = map(int, input().split())
	unit(a, b)
print(-min(lst))


(n, m) = map(int, input().split())
root = list(range(n + 1))
cnt = [1] * (n + 1)

def find(i):
	if i == root[i]:
		return i
	root[i] = find(root[i])
	return root[i]

def union(u, v):
	(fu, fv) = (find(u), find(v))
	if fu == fv:
		return
	root[max(fu, fv)] = min(fu, fv)
	cnt[min(fu, fv)] += cnt[max(fu, fv)]
for i in range(m):
	(u, v) = map(int, input().split())
	union(u, v)
print(max(cnt))


from collections import deque
(n, m) = map(int, input().split())
graph = [[] for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	graph[a - 1].append(b - 1)
	graph[b - 1].append(a - 1)
li = []
seen = [False] * n
for i in range(n):
	if seen[i]:
		continue
	q = deque([i])
	seen[i] = True
	cnt = 1
	while q:
		node = q.popleft()
		for i in graph[node]:
			if seen[i]:
				continue
			seen[i] = True
			cnt += 1
			q.append(i)
	li.append(cnt)
print(max(li))


from sys import stdin, stdout
from collections import defaultdict
import sys
sys.setrecursionlimit(10 ** 7)

def dfs(src):
	global sz
	vis[src] = 1
	sz += 1
	for neigh in g[src]:
		if not vis[neigh]:
			dfs(neigh)
(n, eg) = list(map(int, stdin.readline().split()))
g = defaultdict(list)
for i in range(eg):
	(A, B) = map(int, stdin.readline().split())
	g[A] += [B]
	g[B] += [A]
vis = [0] * (n + 1)
ans = 0
for node in range(1, n + 1):
	if not vis[node]:
		sz = 0
		dfs(node)
		ans = max(ans, sz)
print(ans)


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

class UnionFind:

	def __init__(self, N):
		self.root = list(range(N + 1))
		self.size = [1] * (N + 1)

	def __getitem__(self, x):
		root = self.root
		while root[x] != x:
			root[x] = root[root[x]]
			x = root[x]
		return x

	def merge(self, x, y):
		x = self[x]
		y = self[y]
		if x == y:
			return
		(sx, sy) = (self.size[x], self.size[y])
		if sx < sy:
			(x, y) = (y, x)
			(sx, sy) = (sy, sx)
		self.root[y] = x
		self.size[x] += sy

	def find_max(self):
		return max(self.size)
uf = UnionFind(N)
answer = []
append = answer.append
merge = uf.merge
for i in range(M):
	(a, b) = map(int, input().split())
	merge(a, b)
print(uf.find_max())


def find(x):
	while x != p[x]:
		x = p[x]
	return x

def union(a, b):
	x = find(a)
	global con
	y = find(b)
	if x != y:
		p[y] = p[x] = min(x, y)
		con -= 1
		r[min(x, y)] += r[max(x, y)]
		con = max(con, r[min(x, y)])
(n, m) = map(int, input().split())
p = [i for i in range(n + 1)]
con = 1
r = [1] * (n + 1)
for i in range(m):
	(u, v) = map(int, input().split())
	union(u, v)
print(max(r))


import sys
sys.setrecursionlimit(10 ** 7)

def root(x):
	if rank[x] < 0:
		return x
	rank[x] = root(rank[x])
	return rank[x]

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

def size(x):
	return -rank[root(x)]
(n, m) = map(int, input().split())
rank = [-1 for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	unite(a, b)
ans = 0
for i in range(n):
	ans = max(ans, size(i))
print(ans)


class Unionfind:

	def __init__(self, n):
		self.par = [x for x in range(n)]
		self.num = [1] * n

	def root(self, a):
		if self.par[a] == a:
			return a
		parent = self.root(self.par[a])
		self.par[a] = parent
		return parent

	def unite(self, a, b):
		(ra, rb) = (self.root(a), self.root(b))
		self.par[rb] = ra
		self.num[ra] += self.num[rb]

	def same(self, a, b):
		return self.root(a) == self.root(b)

def main():
	(n, m) = map(int, input().split())
	uf = Unionfind(n)
	for _ in range(m):
		(a, b) = map(int, input().split())
		if uf.same(a - 1, b - 1):
			continue
		uf.unite(a - 1, b - 1)
	print(max(uf.num))
main()


import sys
sys.setrecursionlimit(10 ** 7)

def dfs(u, g, visited):
	if visited[u]:
		return 0
	visited[u] = True
	res = 1
	for v in g[u]:
		res += dfs(v, g, visited)
	return res

def main():
	(n, m) = map(int, input().split())
	g = [[] for _ in range(n + 1)]
	for _ in range(m):
		(a, b) = map(int, input().split())
		g[a].append(b)
		g[b].append(a)
	visited = [False] * (n + 1)
	ans = 0
	for i in range(1, n + 1):
		if visited[i]:
			continue
		ans = max(ans, dfs(i, g, visited))
	print(ans)
main()


(n, m) = map(int, input().split())
adj = [[] for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	adj[a].append(b)
	adj[b].append(a)
ans = 0
vis = [0] * n
for i in range(n):
	if vis[i]:
		continue
	vis[i] = 1
	k = 0
	stk = [i]
	while stk:
		u = stk.pop()
		k += 1
		for v in adj[u]:
			if vis[v]:
				continue
			vis[v] = 1
			stk.append(v)
	ans = max(ans, k)
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
pair = [-1] * n
max_size = 0

def find(x):
	if pair[x] < 0:
		return x
	else:
		pair[x] = find(pair[x])
		return pair[x]

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

def size(x):
	x = find(x)
	return -pair[x]
for _ in range(m):
	(x, y) = map(int, input().split())
	x -= 1
	y -= 1
	unite(x, y)
max_size = max(map(size, range(n)))
print(max_size)


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 __starting_point():
	(n, m) = list(map(int, input().split()))
	unionFind = UnionFind(n)
	for _ in range(m):
		(a, b) = list(map(int, input().split()))
		a -= 1
		b -= 1
		unionFind.union(a, b)
	value = 0
	for i in range(n):
		value = max(value, unionFind.size(i))
	print(value)
__starting_point()


import sys
sys.setrecursionlimit(10000000)
(N, M) = map(int, input().split())
ki = [[] for _ in range(N)]
for _ in range(M):
	(a, b) = map(int, input().split())
	ki[a - 1].append(b - 1)
	ki[b - 1].append(a - 1)
tf = [False for _ in range(N)]

def dfs(v):
	global eda
	tf[v] = True
	eda += 1
	for nv in set(ki[v]):
		if not tf[nv]:
			dfs(nv)
ans = 0
for i in range(N):
	if not tf[i]:
		eda = 0
		dfs(i)
		ans = max(ans, eda)
print(ans)


(N, M) = [int(s) for s in input().split()]
hito = [0 for i in range(N)]
edge = [set() for _ in range(N)]
for i in range(M):
	(a, b) = [int(s) for s in input().split()]
	edge[a - 1].add(b - 1)
	edge[b - 1].add(a - 1)

def dfs(start):
	count = 1
	reach = set()
	reach.add(start)
	hito[start] = 1
	while reach:
		_from = reach.pop()
		for _to in edge[_from]:
			if not _to in reach and hito[_to] == 0:
				reach.add(_to)
				count += 1
				hito[_to] = 1
	return count
ans = set()
for h in range(N):
	if hito[h] == 0:
		ans.add(dfs(h))
print(max(ans))


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)]
(n, m) = map(int, input().split())
a = [list(map(int, input().split())) for i in range(m)]
uf = UnionFind(n)
ans = 0
for i in range(m):
	uf.union(a[i][0] - 1, a[i][1] - 1)
for i in range(n):
	ans = max(ans, uf.size(i))
print(ans)


import sys
sys.setrecursionlimit(10 ** 7)
(N, M) = map(int, input().split())
f = [set() for _ in range(N)]
v = [False for _ in range(N)]
ans = 1
for _ in range(M):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	f[a].add(b)
	f[b].add(a)

def dfs(fi):
	if v[fi]:
		return 0
	v[fi] = True
	cnt = 1
	for fr in f[fi]:
		cnt += dfs(fr)
	return cnt
for i in range(N):
	cnt = dfs(i)
	ans = max(ans, cnt)
print(ans)


(n, m) = list(map(int, input().split()))
par = [i for i in range(n)]
ro = dict()
for i in range(n):
	ro[i] = 1

def root(i):
	if par[i] == i:
		return i
	else:
		a = root(par[i])
		par[i] = a
		return a

def unite(x, y):
	rx = root(x)
	ry = root(y)
	if rx != ry:
		par[rx] = ry
		ro[ry] += ro[rx]
		ro[rx] = 0
for i in range(m):
	(a, b) = list(map(int, input().split()))
	a -= 1
	b -= 1
	unite(a, b)
print(max(ro.values()))


import sys
sys.setrecursionlimit(1 << 30)
input = sys.stdin.readline
(N, M) = map(int, input().split())
e = [-1] * N

def find(x):
	if e[x] < 0:
		return x
	e[x] = find(e[x])
	return e[x]

def join(a, b):
	(a, b) = (find(a), find(b))
	if a == b:
		return
	if e[a] > e[b]:
		(a, b) = (b, a)
	e[a] += e[b]
	e[b] = a
for _ in range(M):
	(x, y) = map(int, input().split())
	join(x - 1, y - 1)
print(-min(e))


import collections
import sys
import resource
sys.setrecursionlimit(1000000)
(n, m) = map(int, input().split(' '))
f = [x for x in range(n)]

def find(x):
	if f[x] == x:
		return x
	root = find(f[x])
	f[x] = root
	return root
for i in range(m):
	(a, b) = map(int, input().split(' '))
	a -= 1
	b -= 1
	if find(a) != find(b):
		f[find(a)] = find(b)
for i in range(n):
	find(i)
print(max(collections.Counter(f).values()))


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


from collections import deque
(n, m) = map(int, input().split())
f = [[] for i in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	f[a].append(b)
	f[b].append(a)
q = deque()
for i in range(n):
	for j in f[i]:
		q.append(j)
	while q:
		p = q.popleft()
		if i != p:
			f[i] += f[p]
			for k in f[p]:
				q.append(k)
			f[p] = []
ans = 1
for i in f:
	cnt = len(list(set(i)))
	ans = max(cnt, ans)
print(ans)


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)]
(N, M) = map(int, input().split())
union_find = UnionFind(N)
for _ in range(M):
	(A, B) = map(int, input().split())
	A -= 1
	B -= 1
	union_find.union(A, B)
answer = 0
for i in range(N):
	answer = max(answer, union_find.size(i))
print(answer)


import sys
sys.setrecursionlimit(10 ** 9)

def f(p, c):
	if P[p] == 0:
		P[p] = c
		for j in range(len(F[p])):
			f(F[p][j], c)
(N, M) = map(int, input().split())
F = [[] for _ in range(N)]
P = [0] * N
for i in range(M):
	(A, B) = map(int, input().split())
	F[A - 1].append(B - 1)
	F[B - 1].append(A - 1)
for i in range(N):
	f(i, i + 1)
C = [0] * N
for i in range(N):
	C[P[i] - 1] += 1
print(max(C))


(N, M) = list(map(int, input().split()))
A = [0] * M
B = [0] * M
R = [0] * N
for i in range(N):
	R[i] = set()
for i in range(M):
	(A[i], B[i]) = list(map(int, input().split()))
	R[A[i] - 1].add(B[i] - 1)
	R[B[i] - 1].add(A[i] - 1)
stack = set()
visited = set()
max_groups = 0
for i in range(N):
	if not i in visited:
		stack.add(i)
		groups = 0
		while True:
			current = stack.pop()
			visited.add(current)
			groups += 1
			stack |= R[current] - visited
			if not stack:
				break
		max_groups = max(max_groups, groups)
print(max_groups)


(n, m) = map(int, input().split())
d = {i: set() for i in range(1, n + 1)}
for i in range(m):
	(a, b) = map(int, input().split())
	d[a].add(b)
	d[b].add(a)
vis = set()
res = 0
for i in range(1, n + 1):
	if i not in vis:
		stack = [i]
		ans = 1
		vis.add(i)
		while stack:
			cur = stack.pop()
			for j in d[cur]:
				if j not in vis:
					vis.add(j)
					ans += 1
					stack.append(j)
		res = max(res, ans)
print(res)


from collections import deque
(N, M) = map(int, input().split())
l = [[] for _ in range(N + 1)]
for _ in range(M):
	(a, b) = map(int, input().split())
	l[a].append(b)
	l[b].append(a)
ans = 1
check = [0] * (N + 1)
for i in range(1, N + 1):
	st = deque([i])
	check[i] = 1
	cnt = 1
	while st:
		s = st.popleft()
		for t in l[s]:
			if check[t] == 0:
				check[t] = 1
				st.append(t)
				cnt += 1
	ans = max(ans, cnt)
print(ans)


from collections import deque
(N, M) = map(int, input().split())
A = [set() for i in range(N + 1)]
for i in range(M):
	(a, b) = map(int, input().split())
	A[a].add(b)
	A[b].add(a)
B = [0 for i in range(N + 1)]
C = [0 for i in range(N + 1)]
d = deque()
n = 1
for i in range(1, N + 1):
	if B[i] != 0:
		continue
	d.append(i)
	C[n] += 1
	B[i] = n
	while len(d):
		e = d.pop()
		for k in A[e]:
			if B[k] == 0:
				d.append(k)
				C[n] += 1
				B[k] = 1
	n += 1
print(max(C))


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

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return 0
	if x < y:
		(x, y) = (y, x)
	par[x] = y
(n, m) = map(int, input().split())
par = [i for i in range(n + 1)]
for _ in range(m):
	(i, j) = map(int, input().split())
	unite(i, j)
ans = [0] * (n + 1)
for i in range(n + 1):
	find(i)
for i in par:
	ans[i] += 1
print(max(ans))


import sys
sys.setrecursionlimit(10000000)
(N, M) = list(map(int, input().split()))
d = {i: [] for i in range(1, N + 1)}
for _ in range(M):
	(a, b) = list(map(int, input().split()))
	d[a].append(b)
	d[b].append(a)
visited = [False for _ in range(N + 1)]

def visit(x):
	if visited[x]:
		return 0
	visited[x] = True
	z = 1
	for y in d[x]:
		z += visit(y)
	return z
m = 1
for i in range(1, N + 1):
	r = visit(i)
	if m < r:
		m = r
print(m)


import sys
input = sys.stdin.readline

def unite(x, y):
	rx = root(x)
	ry = root(y)
	if rank[rx] > rank[ry]:
		parent[ry] = rx
		size[rx] += size[ry]
	else:
		parent[rx] = ry
		size[ry] += size[rx]
		if rank[rx] == rank[ry]:
			rank[ry] += 1

def root(x):
	if x != parent[x]:
		return root(parent[x])
	return x

def same(x, y):
	return root(x) == root(y)
(n, m) = map(int, input().split())
parent = list(range(n))
rank = [0] * n
size = [1] * n
for i in range(m):
	(a, b) = map(int, input().split())
	if same(a - 1, b - 1) == False:
		unite(a - 1, b - 1)
print(max(size))


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 issame(self, x, y):
		return self.find[x] == self.find(y)

def __starting_point():
	(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)
	ans = 0
	for i in range(N):
		ans = max(ans, uf.size(i))
	print(ans)
__starting_point()


from collections import deque
(n, m) = map(int, input().split())
E = [[] for _ in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	E[a].append(b)
	E[b].append(a)
flag = [True for _ in range(n)]
ans = 0
for i in range(n):
	if flag[i]:
		counter = 1
		flag[i] = False
		que = deque([i])
		while que:
			now = deque.popleft(que)
			for j in E[now]:
				if flag[j]:
					deque.append(que, j)
					counter += 1
					flag[j] = False
		ans = max(ans, counter)
print(ans)


import sys
sys.setrecursionlimit(1000000)

def DFS(i):
	if done[i]:
		ans[-1] += 1
		done[i] = False
		for g in G[i]:
			if done[g]:
				DFS(g)
	else:
		return p
(N, M) = map(int, input().split())
G = [[] for _ in range(N)]
done = [True for _ in range(N)]
for i in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	G[a].append(b)
	G[b].append(a)
ans = []
for j in range(N):
	ans.append(0)
	if done[j]:
		DFS(j)
print(max(ans))


from collections import deque
from bisect import bisect_left as bl
f = lambda : map(int, input().split())
(N, M) = f()
D = [[] for _ in [0] * (N + 1)]
F = [0] * (N + 1)
F[0] = 1
for _ in range(M):
	(a, b) = f()
	D[a].append(b)
	D[b].append(a)
q = deque()
res = 0
while bl(F, 1):
	index = bl(F, 1) - 1
	q.append(index)
	tmp = 0
	while q:
		k = q.pop()
		if F[k] != 1:
			tmp += 1
			F[k] = 1
			for d in list(set(D[k])):
				if F[d] != 1:
					q.append(d)
			D[k] = 0
	res = max(res, tmp)
print(res)


(N, M) = map(int, input().split())
r = [-1] * (N + 1)

def root(x):
	if r[x] < 0:
		return x
	return root(r[x])
for i in range(M):
	(x, y) = map(int, input().split())
	x = root(x)
	y = root(y)
	if x == y:
		continue
	if r[x] > r[y]:
		(x, y) = (y, x)
	r[x] += r[y]
	r[y] = x
print(-min(r))


from collections import Counter

def solve(n, m, a, b):
	parents = list(range(n + 1))

	def root(x):
		if parents[x] != x:
			parents[x] = root(parents[x])
		return parents[x]
	for (u, v) in zip(a, b):
		u = root(u)
		v = root(v)
		if u > v:
			(u, v) = (v, u)
		if u != v:
			parents[v] = u
	return max(Counter(map(root, parents)).values())
(n, m) = map(int, input().split())
if m > 0:
	(a, b) = zip(*[map(int, input().split()) for i in range(m)])
else:
	(a, b) = ([], [])
print(solve(n, m, a, b))


(n, m) = map(int, input().split())
tree = [0] + [i + 1 for i in range(n)]
size = [0] + [1 for i in range(n)]

def find(c):
	pc = tree[c]
	if pc == c:
		return pc
	else:
		return find(pc)
for _ in range(m):
	(a, b) = map(int, input().split())
	(pa, pb) = (find(a), find(b))
	if pa != pb:
		if size[pa] < size[pb]:
			tree[pa] = pb
			(size[pa], size[pb]) = (size[pa] + size[pb], size[pa] + size[pb])
		else:
			tree[pb] = pa
			(size[pa], size[pb]) = (size[pa] + size[pb], size[pa] + size[pb])
print(max(size))


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


(N, M) = map(int, input().split())
f = [set() for i in range(N)]
v = [False] * N
g = []
for i in range(0, M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	f[a].add(b)
	f[b].add(a)
for i in range(0, N):
	if v[i]:
		continue
	s = set()
	q = [i]
	while len(q) > 0:
		p = q.pop()
		v[p] = True
		s.add(p)
		for x in f[p]:
			if v[x]:
				continue
			q.append(x)
	g.append(s)
z = 0
for x in g:
	z = max(z, len(x))
print(z)


(N, M) = map(int, input().split())
F = [list(map(int, input().split())) for i in range(M)]
d = [-1] * N

def find(x):
	if d[x] < 0:
		return x
	d[x] = find(d[x])
	return d[x]

def union(x, y):
	(x, y) = (find(x), find(y))
	if x == y:
		return
	if d[x] > d[y]:
		(x, y) = (y, x)
	d[x] += d[y]
	d[y] = x
for f in F:
	union(f[0] - 1, f[1] - 1)
print(-min(d))


import sys
input = sys.stdin.readline
(N, M) = map(int, input().split())
F = [i for i in range(N)]

def find(n):
	if F[n] == n:
		return n
	ret = find(F[n])
	F[n] = ret
	return ret

def union(n, m):
	(i, j) = (find(n), find(m))
	F[max(i, j)] = min(i, j)
for _ in range(M):
	(A, B) = map(int, input().split())
	A -= 1
	B -= 1
	union(A, B)
cnt = [0 for _ in range(N)]
for i in range(N):
	cnt[find(i)] += 1
print(max(cnt))


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())
uf = UnionFind(n)
for _ in range(m):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	uf.union(a, b)
print(min(uf.parents) * -1)


def root(x):
	if F[x] < 0:
		return x
	else:
		F[x] = root(F[x])
		return F[x]

def unite(x, y):
	x = root(x)
	y = root(y)
	if x == y:
		return
	if x > y:
		(x, y) = (y, x)
	F[x] += F[y]
	F[y] = x
(N, M) = map(int, input().split())
F = [-1] * N
for m in range(M):
	(a, b) = map(int, input().split())
	unite(a - 1, b - 1)
ans = 0
for f in F:
	ans = min(ans, f)
print(-ans)


import sys
sys.setrecursionlimit(int(200000.0 + 999))

def solve():
	(n, m) = map(int, input().split()[0:2])
	fa = list(range(0, n + 1))
	sz = [1] * (n + 1)

	def gf(x):
		if x == fa[x]:
			return x
		fa[x] = gf(fa[x])
		return fa[x]
	for i in range(m):
		(a, b) = map(gf, map(int, input().split()[0:2]))
		if a != b:
			fa[a] = b
			sz[b] += sz[a]
	ans = 1
	for i in range(1, n + 1):
		ans = max(ans, sz[gf(i)])
	return ans
print(solve())


(N, M) = map(int, input().split())
par = [i for i in range(N + 1)]
size = [1 for i in range(N + 1)]

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

def union(x, y):
	if find(x) != find(y):
		(x, y) = (par[x], par[y])
		par[y] = par[x]
		size[x] += size[y]
res = N
for i in range(M):
	(s, e) = map(int, input().split())
	union(s, e)
print(max(size))


(N, M) = map(int, input().split())
friend = [[] for _ in range(N)]
for i in range(M):
	(A, B) = map(int, input().split())
	friend[A - 1].append(B - 1)
	friend[B - 1].append(A - 1)
ans = 0
ischecked = [0] * N
for i in range(N):
	if ischecked[i] == 1:
		continue
	group = 1
	ischecked[i] = 1
	ship = friend[i]
	while ship:
		nex = ship.pop()
		if ischecked[nex] == 1:
			continue
		ischecked[nex] = 1
		group += 1
		ship.extend(friend[nex])
	ans = max(ans, group)
print(ans)


import sys
input = sys.stdin.readline
from collections import deque
(n, m) = map(int, input().split())
graph = [set() for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	if b - 1 not in graph[a - 1]:
		graph[a - 1].add(b - 1)
	if a - 1 not in graph[b - 1]:
		graph[b - 1].add(a - 1)
clusters = 0
v = [False] * n
for i in range(n):
	if not v[i]:
		v[i] = True
		q = deque([i])
		cluster = 0
		while q:
			node = q.popleft()
			cluster += 1
			for j in graph[node]:
				if not v[j]:
					v[j] = True
					q.append(j)
		clusters = max(clusters, cluster)
print(clusters)


(n, m) = map(int, input().split())
grid = [set() for i in range(n)]
for i in range(m):
	(u, v) = map(int, input().split())
	u -= 1
	v -= 1
	grid[u].add(v)
	grid[v].add(u)
cnt = 0
best = 0
visited = set()
import sys
sys.setrecursionlimit(1000000)

def dfs(x):
	global cnt
	if x in visited:
		return
	cnt += 1
	visited.add(x)
	for i in grid[x]:
		dfs(i)
for i in range(n):
	cnt = 0
	dfs(i)
	best = max(best, cnt)
print(best)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
root = [-1] * n

def find_root(x):
	if root[x] < 0:
		return x
	else:
		root[x] = find_root(root[x])
		return root[x]

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

def size(x):
	x = find_root(x)
	return -root[x]
for i in range(m):
	(x, y) = map(int, input().split())
	x -= 1
	y -= 1
	unite(x, y)
max_size = max(map(size, range(n)))
print(max_size)


import math
import string
import itertools
import fractions
import heapq
import collections
import re
import array
import bisect
import sys
import random
import time
inf = 10 ** 9

class UnionFind:

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

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

	def unite(self, x: int, y: int):
		(x, y) = (self.root(x), self.root(y))
		if x == y:
			return
		if self.r[x] > self.r[y]:
			(x, y) = (y, x)
		self.r[x] += self.r[y]
		self.r[y] = x

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

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.unite(a - 1, b - 1)
	print(-min(uf.r))

def __starting_point():
	main()
__starting_point()


class UnionFind:
	from typing import List, Set

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

	def merge(self, x, y) -> int:
		x = self.leader(x)
		y = self.leader(y)
		if x == y:
			return 0
		if self.parent[x] > self.parent[y]:
			(x, y) = (y, x)
		self.parent[x] += self.parent[y]
		self.parent[y] = x
		return self.parent[x]

	def same(self, x, y) -> bool:
		return self.leader(x) == self.leader(y)

	def leader(self, x) -> int:
		if self.parent[x] < 0:
			return x
		else:
			self.parent[x] = self.leader(self.parent[x])
			return self.parent[x]

	def size(self, x) -> int:
		return -self.parent[self.leader(x)]

	def groups(self) -> List[Set[int]]:
		groups = dict()
		for i in range(self.n):
			p = self.leader(i)
			if not groups.get(p):
				groups[p] = set()
			groups[p].add(i)
		return list(groups.values())
(n, m) = map(int, input().split())
uf = UnionFind(n)
for i in range(m):
	(a, b) = map(int, input().split())
	uf.merge(a - 1, b - 1)
grp = uf.groups()
ans = 0
for i in range(len(grp)):
	if len(grp[i]) > ans:
		ans = len(grp[i])
print(ans)


from sys import stdin
nii = lambda : map(int, stdin.readline().split())
lnii = lambda : list(map(int, stdin.readline().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 same(self, x, y):
		return self.find(x) == self.find(y)

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

	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) = nii()
uf = UnionFind(n)
for i in range(m):
	(a, b) = nii()
	a -= 1
	b -= 1
	uf.union(a, b)
root = uf.roots()
ans = 0
for i in root:
	ans = max(ans, uf.size(i))
print(ans)


from collections import deque
(n, m) = map(int, input().split())
edge = [[] for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	edge[a].append(b)
	edge[b].append(a)
visited = [0] * n

def bfs(s):
	q = deque([s])
	visited[s] = 1
	cnt = 1
	while q:
		x = q.popleft()
		for nx in edge[x]:
			if visited[nx] == 0:
				visited[nx] = 1
				cnt += 1
				q.append(nx)
	return cnt
ans = 0
for i in range(n):
	if visited[i] == 0:
		ans = max(ans, bfs(i))
print(ans)


(n, m) = [int(x) for x in input().split()]
l = [[] for i in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	l[a - 1].append(b - 1)
	l[b - 1].append(a - 1)
done = [0] * n

def dfs(j):
	que = [j]
	cnt = 1
	done[j] = 1
	while que:
		now = que.pop(0)
		for i in l[now]:
			if done[i] != 1:
				que.append(i)
				done[i] = 1
				cnt += 1
	return cnt
ma = 0
for j in range(n):
	if done[j] != 1:
		now = dfs(j)
	else:
		now = 0
	ma = max(now, ma)
print(ma)


from collections import Counter
(N, M) = map(int, input().split())

def parent(par, i):
	depth = 0
	while par[i] != i:
		i = par[i]
		depth += 1
	return (i, depth)

def union(par, a, b):
	(pa, da) = parent(par, a)
	(pb, db) = parent(par, b)
	if da < db:
		par[pa] = par[pb]
	else:
		par[pb] = par[pa]
par = [i for i in range(N)]
for _ in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	union(par, a, b)
c = Counter()
for i in range(N):
	c.update([parent(par, i)[0]])
print(c.most_common(1)[0][1])


(n, m) = map(int, input().split())
l = [set() for _ in range(n + 1)]
for i in range(m):
	(a, b) = map(int, input().split())
	l[a].add(b)
	l[b].add(a)
from collections import deque
vi = [0 for _ in range(n + 1)]
st = deque(([i, i] for i in range(1, n + 1)))
while st:
	(c, d) = st.popleft()
	if vi[c] == 0:
		vi[c] = d
		for m in l[c]:
			st.appendleft([m, d])
from collections import Counter
s = Counter(vi)
mx = 0
for m in s.values():
	mx = max(mx, m)
print(mx)


from collections import defaultdict

def bfs(s):
	q = [s]
	visited[s] = True
	c = 0
	while q != []:
		p = q[0]
		c += 1
		del q[0]
		for node in adj[p]:
			if not visited[node]:
				visited[node] = True
				q.append(node)
	return c
(n, m) = map(int, input().split())
adj = defaultdict(list)
visited = [False] * (n + 1)
ans = 0
for _ in range(m):
	(a, b) = map(int, input().split())
	adj[a].append(b)
	adj[b].append(a)
for i in range(1, n + 1):
	if not visited[i]:
		ans = max(ans, bfs(i))
print(ans)


from collections import *
(N, M) = 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)


import sys
sys.setrecursionlimit(10 ** 7)

def dfs(v, visited, counter):
	visited[v] = 1
	for nv in G[v]:
		if visited[nv]:
			continue
		visited[nv] = 1
		counter.append(1)
		dfs(nv, visited, counter)
	return
(n, m) = map(int, input().split())
G = [[] for _ in range(n)]
visited = [0] * n
for i in range(m):
	(a, b) = map(int, input().split())
	G[a - 1].append(b - 1)
	G[b - 1].append(a - 1)
max_friends = 0
for i in range(n):
	if visited[i]:
		continue
	friends = []
	dfs(i, visited, friends)
	max_friends = max(max_friends, sum(friends) + 1)
print(max_friends)


(N, M) = map(int, input().split())
r = [i for i in range(N + 1)]
n = [0 for i in range(N + 1)]
buf = []

def root(x):
	if x == r[x]:
		return x
	else:
		r[x] = root(r[x])
		return r[x]

def unite(x, y):
	rx = root(x)
	ry = root(y)
	if rx < ry:
		r[ry] = rx
	elif rx > ry:
		r[rx] = ry
for _ in range(M):
	(a, b) = map(int, input().split())
	unite(a, b)
for x in range(1, N + 1):
	if r[x] != x and r[r[x]] != r[x]:
		_ = root(x)
for x in r[1:]:
	n[x] += 1
ans = max(n[1:])
print(ans)


import sys
input = lambda : sys.stdin.readline().rstrip()
(n, m) = map(int, input().split())
a = [-1] * (n + 1)
st = set()
for i in range(m):
	(x, y) = map(int, input().split())
	chk = (min(x, y), max(x, y))
	if chk in st:
		continue
	st.add(chk)
	while a[x] >= 0:
		x = a[x]
	while a[y] >= 0:
		y = a[y]
	if x == y:
		continue
	if a[x] < a[y]:
		a[x] += a[y]
		a[y] = x
	else:
		a[y] += a[x]
		a[x] = y
cnt = 0
for i in a[1:]:
	if i < 0:
		cnt = max(cnt, -i)
print(cnt)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = 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) = map(int, input().split())
	a -= 1
	b -= 1
	unite(a, b)
print(-min(root))


import queue
(n, m) = map(int, input().split())
a = [[] for j in range(n)]
for i in range(0, m):
	(b, c) = map(int, input().split())
	a[b - 1].append(c - 1)
	a[c - 1].append(b - 1)
re = [0 for i in range(n)]
le = [0]
for i in range(0, n):
	if re[i] == 0:
		ans = queue.Queue()
		ans.put(i)
		le.append(1)
		re[i] = 1
		while ans.empty() == False:
			d = ans.get()
			for j in range(len(a[d])):
				if re[a[d][j]] == 0:
					ans.put(a[d][j])
					re[a[d][j]] = 1
					le[-1] += 1
print(max(le))


import sys
sys.setrecursionlimit(1500)

class UnionFind:

	def __init__(self, N):
		self.par = [-1 for i in range(N)]

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

	def unite(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
		return True

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

	def size(self, x):
		return -self.par[self.root(x)]
(N, M) = list(map(int, input().split()))
uf = UnionFind(N)
for _ in range(M):
	(A, B) = [int(x) - 1 for x in input().split()]
	uf.unite(A, B)
print(-min(uf.par))


(N, M) = map(int, input().split())
f = [[] for i in range(N)]
for i in range(M):
	(A, B) = map(int, input().split())
	f[A - 1].append(B - 1)
	f[B - 1].append(A - 1)
from collections import deque
d = deque()
x = [-1] * N
for i in range(N):
	if x[i] == -1:
		x[i] = i
		d.append(f[i])
	while len(d) > 0:
		z = d.popleft()
		for j in z:
			if x[j] == -1:
				x[j] = i
				d.append(f[j])
import collections
ans = collections.Counter(x)
print(ans.most_common()[0][1])


(N, M) = list(map(int, input().split()))
l = [[] for i in range(N)]
l_c = [0 for i in range(N)]
for i in range(M):
	(a, b) = list(map(int, input().split()))
	a -= 1
	b -= 1
	l[a].append(b)
	l[b].append(a)
from collections import deque

def search(start):
	cnt = 1
	que = deque([start])
	l_c[start] = 1
	while que:
		A = que.popleft()
		for i in l[A]:
			if l_c[i] == 0:
				cnt += 1
				l_c[i] = 1
				que.append(i)
	return cnt
ans = 0
for i in range(N):
	if l_c[i] == 0:
		ans = max(ans, search(i))
print(ans)


from collections import deque
(N, M) = map(int, input().split())
friends = [[] for _ in range(N + 1)]
for __ in range(M):
	(a, b) = map(int, input().split())
	friends[a].append(b)
	friends[b].append(a)
checked = [0 for ___ in range(N + 1)]
answer = 1
for i in range(1, N + 1):
	friend = deque(friends[i])
	cnt = 0
	while len(friend) > 0:
		f = friend.popleft()
		if checked[f] != 0:
			continue
		else:
			checked[f] = 1
			cnt += 1
			for ff in friends[f]:
				friend.append(ff)
	answer = max(answer, cnt)
print(answer)


(n, m) = map(int, input().split())
par = [-1] * n

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

def union(x, y):
	(p, q) = (find(x), find(y))
	if p == q:
		return
	if p > q:
		(p, q) = (q, p)
	par[p] += par[q]
	par[q] = p

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

def same(x, y):
	return find(x) == find(y)
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	union(a, b)
mx = 0
for i in par:
	if i < 0:
		mx = max(mx, -i)
print(mx)


from collections import deque
(n, m) = list(map(int, input().split()))
G = [[] for _ in range(n)]
for i in range(m):
	(a, b) = list(map(int, input().split()))
	a -= 1
	b -= 1
	G[a].append(b)
	G[b].append(a)
que = deque()
dist = [-1] * n
ans = 0
for i in range(n):
	if dist[i] != -1:
		continue
	dist[i] == 0
	que.append(i)
	cnt = 0
	while len(que):
		v = que.popleft()
		vs = G[v]
		for nv in vs:
			if dist[nv] == -1:
				dist[nv] = dist[v] + 1
				cnt += 1
				que.append(nv)
	ans = max(cnt, ans)
if m == 0:
	print(1)
else:
	print(ans)


(n, m) = map(int, input().split())
g = [set() for i in range(n)]
visited = [False] * n
group = []
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	g[a].add(b)
	g[b].add(a)
for i in range(n):
	if visited[i]:
		continue
	s = set()
	q = [i]
	while len(q) > 0:
		p = q.pop()
		visited[p] = True
		s.add(p)
		for x in g[p]:
			if visited[x]:
				continue
			q.append(x)
	group.append(s)
ans = 0
for x in group:
	ans = max(ans, len(x))
print(ans)


class UnionFind:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rnk = [0] * (n + 1)

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

	def Unite(self, x, y):
		x = self.Find_Root(x)
		y = self.Find_Root(y)
		if x == y:
			return
		elif self.rnk[x] > self.rnk[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rnk[x] == self.rnk[y]:
				self.rnk[y] += 1

	def isSameGroup(self, x, y):
		return self.Find_Root(x) == self.Find_Root(y)

	def Count(self, x):
		return -self.root[self.Find_Root(x)]

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.Unite(a, b)
	for i in range(n):
		i += 1
		uf.isSameGroup(i, i)
	ans = 0
	for i in range(n):
		ans = max(ans, -uf.root[i + 1])
	print(ans)
main()


import networkx as nx
import sys
G = nx.Graph()
(n, m) = list(map(int, input().split()))
if m == 0:
	print(1)
	return
for i in range(m):
	(a, b) = list(map(int, input().split()))
	G.add_edge(a, b)
largest_cc = max(nx.connected_components(G), key=len)
print(len(largest_cc))


class UnionFind:

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

	def find(self, x):
		if self.parents[x] == x:
			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 0
		elif x < y:
			self.parents[y] = x
		else:
			self.parents[x] = y
		return 1
from collections import Counter
(n, m) = list(map(int, input().split()))
uf = UnionFind(n)
for _ in range(m):
	(a, b) = list(map(int, input().split()))
	uf.unite(a, b)
roots = []
for num in uf.parents:
	roots.append(uf.find(num))
count_roots = Counter(roots)
print(max(count_roots.values()))


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


(n, m) = map(int, input().split())
flag = list(range(n + 1))
flagnum = [0] * (n + 1)

def takeflag(p):
	stock = []
	while flag[flag[p]] != flag[p]:
		stock.append(p)
		p = flag[p]
	p = flag[p]
	for i in stock:
		flag[i] = p
	return p
for i in range(m):
	(a, b) = map(int, input().split())
	(a, b) = map(takeflag, (a, b))
	(a, b) = (min(a, b), max(a, b))
	flag[a] = b
for i in range(n + 1):
	flag[i] = takeflag(i)
	flagnum[flag[i]] += 1
print(max(flagnum))


def input_int():
	return int(input())

def int1(x):
	return int(x) - 1

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

def input_to_int_tuple():
	return tuple(map(int, input().split()))

def input_to_int_tuple_minus1():
	return tuple(map(int1, input().split()))

def main():
	(N, M) = input_to_int_map()
	AB = (input_to_int_tuple() for i in range(M))
	from collections import defaultdict
	friends = defaultdict(lambda : -1)

	def root(x):
		temp = friends[x]
		if temp < 0:
			return x
		temp2 = root(temp)
		friends[x] = temp2
		return temp2
	for (a, b) in AB:
		a = root(a)
		b = root(b)
		if a == b:
			continue
		if friends[a] > friends[b]:
			temp = a
			a = b
			b = temp
		friends[a] += friends[b]
		friends[b] = a
	ret = 0
	for i in range(1, N + 1):
		temp = root(i)
		ret = max(ret, -friends[temp])
	print(ret)

def __starting_point():
	main()
__starting_point()


from collections import deque
(N, M) = map(int, input().split())
friends = [[] for _ in range(N)]
for _ in range(M):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	friends[a].append(b)
	friends[b].append(a)
check = [False] * N
ans = 0
for i in range(N):
	if check[i] == False:
		check[i] = True
		D = deque(friends[i])
		tmp = 1
		while D:
			f = D.popleft()
			if check[f] == False:
				check[f] = True
				tmp += 1
				for j in friends[f]:
					D.append(j)
		ans = max(ans, tmp)
print(ans)


(n, m) = map(int, input().split())
l = [[] for i in range(n)]
for i in range(m):
	(a, b) = map(int, input().split())
	l[a - 1].append(b - 1)
	l[b - 1].append(a - 1)
mp = [False] * n
mcnt = 0
for i in range(n):
	if mp[i]:
		continue
	queue = [i]
	cnt = 0
	mp[i] = True
	while queue:
		num = queue.pop()
		cnt += 1
		target = set(l[num])
		for x in target:
			if mp[x]:
				continue
			mp[x] = True
			queue.append(x)
	mcnt = max(cnt, mcnt)
print(mcnt)


(n, m) = map(int, input().split())
par = [0] * (n + 1)
group = [1] * (n + 1)
for i in range(1, n + 1):
	par[i] = i

def root(x):
	if par[x] == x:
		return x
	return root(par[x])

def union(x, y):
	rx = root(x)
	ry = root(y)
	if rx == ry:
		return
	par[max(rx, ry)] = min(rx, ry)
	group[min(rx, ry)] += group[max(rx, ry)]
for _ in range(m):
	(f1, f2) = map(int, input().split())
	union(f1, f2)
print(max(group))


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

def find(x):
	g = x
	while g != a[g]:
		g = a[g]
	a[x] = g
	return g
for _ in range(m):
	(x, y) = map(int, input().split())
	(x, y) = (find(x - 1), find(y - 1))
	if x == y:
		continue
	a[y] = x
count = [0] * n
for i in range(n):
	count[find(i)] += 1
print(max(count))


class UnionFind:

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

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

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

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

	def roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]
(N, M) = list(map(int, input().split()))
uf = UnionFind(N)
for i in range(M):
	(A, B) = list(map(int, input().split()))
	a = uf.find(A - 1)
	b = uf.find(B - 1)
	uf.union(a, b)
ans = 0
for i in uf.roots():
	ans = max(uf.size(i), ans)
print(ans)


(n, m) = map(int, input().split())
global fri
fri = []
global tab
tab = [0] * n

def run(nn):
	global cnt
	if tab[nn]:
		return
	tab[nn] = 1
	cnt += 1
	for i in fri[nn]:
		que.append(i)
for i in range(n):
	fri.append([])
for i in range(m):
	(a, b) = map(int, input().split())
	fri[a - 1].append(b - 1)
	fri[b - 1].append(a - 1)
i = 0
mx = 0
while i < n:
	if tab[i]:
		i += 1
		continue
	que = [i]
	cnt = 0
	while len(que) != 0:
		run(que.pop())
	mx = max(cnt, mx)
	i += 1
print(mx)


import collections
(N, M) = map(int, input().split())
dic = {i + 1: set() for i in range(N)}
for m in range(M):
	(A, B) = map(int, input().split())
	dic[A].add(B)
	dic[B].add(A)
vi_n = [i + 1 for i in range(N)]
vi_d = set()
stack = [i + 1 for i in range(N)]
while len(vi_d) < N:
	v = stack.pop()
	if v in vi_d:
		continue
	vi_d.add(v)
	for node in dic[v]:
		stack.append(node)
		vi_n[node - 1] = vi_n[v - 1]
c = collections.Counter(vi_n)
c_l = list(c.values())
print(max(c_l))


MOD = 10 ** 9 + 7
(N, M) = list(map(int, input().split()))
AB_M = [list(map(int, input().split())) for _ in range(M)]
parents = [-1] * (N + 1)

def find(x):
	if parents[x] < 0:
		return x
	else:
		parents[x] = find(parents[x])
		return parents[x]

def union(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	if parents[x] > parents[y]:
		(x, y) = (y, x)
	parents[x] += parents[y]
	parents[y] = x
for ab in AB_M:
	union(ab[0], ab[1])
ans = -min(parents)
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(N, M) = 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 -r(x)
for i in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	unite(a, b)
max_size = -min(root)
print(max_size)


from collections import deque
(N, M) = map(int, input().split())
S = [set() for i in range(N)]
visited = [-1] * N
colorcount = [-1] * N
for i in range(M):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	S[a].add(b)
	S[b].add(a)
q = deque()
for i in range(N):
	q.append(i)
	color = i
	cnt = 1
	while len(q):
		nt = q.popleft()
		if visited[nt] != -1:
			continue
		visited[nt] = color
		q.extend(S[nt])
		cnt += 1
	colorcount[color] = cnt - 1
print(max(colorcount))


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
friend = [set() for i in range(n)]
for i in range(m):
	a = list(map(int, input().split()))
	a.sort()
	(x, y) = (a[0] - 1, a[1] - 1)
	friend[x].add(y)
	friend[y].add(x)

def dfs(s):
	if vis[s] == False:
		vis[s] = True
		ary.append(s)
		for j in friend[s]:
			dfs(j)
vis = [False for i in range(n)]
ans = 0
for i in range(n):
	ary = []
	dfs(i)
	ans = max(ans, len(ary))
print(ans)


(N, M) = list(map(int, input().split()))
ABs = [list(map(int, input().split())) for _ in range(M)]
par = [i for i in range(N + 1)]
size = [1 for _ in range(N + 1)]

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

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

def unite(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return 0
	par[x] = y
	size[y] = size[x] + size[y]
	size[x] = 0
for AB in ABs:
	unite(AB[0], AB[1])
print(max(size))


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 unite(self, x, y):
		rx = self.root(x)
		ry = self.root(y)
		if rx == ry:
			return
		self.par[ry] += self.par[rx]
		self.par[rx] = ry
(N, M) = map(int, input().split())
uf = UnionFind(N)
for i in range(M):
	(A, B) = map(lambda x: int(x), input().split())
	(A, B) = (A - 1, B - 1)
	uf.unite(A, B)
print(-min(uf.par))


from collections import Counter
import sys
sys.setrecursionlimit(10 ** 6)
(N, M) = map(int, input().split())
parent = [-1] * N

def union(x, y):
	x = find(x)
	y = find(y)
	if x == y:
		return
	parent[x] = y

def find(x):
	if parent[x] == -1:
		return x
	res = parent[x] = find(parent[x])
	return res
for _ in range(M):
	(a, b) = map(int, input().split())
	union(a - 1, b - 1)
count = Counter((find(i) for i in range(N)))
print(count.most_common(1)[0][1])


class union_find:

	def __init__(self, n):
		self.n = n
		self.root = [-1] * (n + 1)
		self.rank = [0] * (n + 1)

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

	def unite(self, x, y):
		x = self.find_root(x)
		y = self.find_root(y)
		if x == y:
			return
		elif self.rank[x] > self.rank[y]:
			self.root[x] += self.root[y]
			self.root[y] = x
		else:
			self.root[y] += self.root[x]
			self.root[x] = y
			if self.rank[x] == self.rank[y]:
				self.rank[y] += 1

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

	def cnt(self, x):
		return -self.root[self.find_root(x)]
(n, m) = map(int, input().split())
g = union_find(n)
ans = 0
for _ in range(m):
	(a, b) = map(int, input().split())
	g.unite(a, b)
for i in range(1, n + 1):
	ans = max(ans, g.cnt(i))
print(ans)


(n, m) = map(int, input().split())
a = [1] * (n + 1)
b = [0] * (n + 1)
for i in range(m):
	(x, y) = 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))


def find(target):
	if parent[target] < 0:
		return target
	else:
		parent[target] = find(parent[target])
		return parent[target]

def is_same(x, y):
	return find(x) == find(y)

def union(x, y):
	root_x = find(x)
	root_y = find(y)
	if root_x == root_y:
		return
	if parent[root_x] > parent[root_y]:
		(root_x, root_y) = (root_y, root_x)
	parent[root_x] += parent[root_y]
	parent[root_y] = root_x

def members(n, x):
	root = find(x)
	return [i for i in range(n) if find(i) == root]

def get_size(x):
	return -parent[find(x)]

def get_root():
	return [i for (i, root) in enumerate(parent) if root < 0]
(n, m) = map(int, input().split())
parent = [-1 for _ in range(n)]
for _ in range(m):
	(a, b) = map(lambda x: int(x) - 1, input().split())
	union(a, b)
ans = 0
for i in range(n):
	ans = max(ans, get_size(i))
print(ans)


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 roots(self):
		return [i for (i, x) in enumerate(self.parents) if x < 0]
(N, M) = map(int, input().split())
uf = UnionFind(N)
for _ in range(M):
	(a, b) = map(int, input().split())
	uf.unite(a - 1, b - 1)
ans = 0
for r in uf.roots():
	s = uf.size(r)
	ans = max(ans, s)
print(ans)


from collections import defaultdict
(N, M) = map(int, input().split())
edges = defaultdict(set)
for _ in range(M):
	(a, b) = map(lambda x: int(x) - 1, input().split())
	edges[a].add(b)
	edges[b].add(a)
ans = 0
visited = [False] * N

def dfs(i):
	stack = [i]
	ans = 0
	while stack:
		i = stack.pop()
		if visited[i]:
			continue
		ans += 1
		visited[i] = True
		for dest in edges[i]:
			stack.append(dest)
	return ans
for i in range(N):
	ans = max(ans, dfs(i))
print(ans)


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

def find(x):
	if par[x] == x:
		return x
	else:
		par[x] = find(par[x])
		return par[x]
for _ in range(m):
	(a, b) = map(int, input().split())
	A = find(a)
	B = find(b)
	par[max(A, B)] = par[min(A, B)]
l = []
for i in range(1, n + 1):
	l.append(find(i))
l = collections.Counter(l)
print(max(l.values()))


from sys import setrecursionlimit

def find(par, i):
	if par[i] < 0:
		return i
	par[i] = find(par, par[i])
	return par[i]

def unite(par, i, j):
	ri = find(par, i)
	rj = find(par, j)
	if ri == rj:
		return
	par[rj] += par[ri]
	par[ri] = rj
setrecursionlimit(10 ** 6)
(n, m) = map(int, input().split())
parent = [-1] * n
for _ in range(m):
	(a, b) = map(lambda x: int(x) - 1, input().split())
	unite(parent, a, b)
print(-min(parent))


from sys import setrecursionlimit, stdin

def find(parent, i):
	t = parent[i]
	if t < 0:
		return i
	t = find(parent, t)
	parent[i] = t
	return t

def unite(parent, i, j):
	i = find(parent, i)
	j = find(parent, j)
	if i == j:
		return
	parent[j] += parent[i]
	parent[i] = j
readline = stdin.readline
setrecursionlimit(10 ** 6)
(N, M) = map(int, readline().split())
parent = [-1] * N
for _ in range(M):
	(A, B) = map(lambda x: int(x) - 1, readline().split())
	unite(parent, A, B)
print(-min(parent))


import sys
sys.setrecursionlimit(10 ** 7)

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

def unite(x, y):
	(x, y) = (root(x), root(y))
	if x == y:
		return
	par[x] = y

def is_same(x, y):
	return root(x) == root(y)
(n, m) = map(int, input().split())
par = [i for i in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	(a, b) = (a - 1, b - 1)
	unite(a, b)
cnt = [0] * n
for p in par:
	cnt[root(p)] += 1
print(max(cnt))


(N, M) = map(int, input().split())
F = [set() for _ in range(N)]
for _ in range(M):
	(a, b) = map(lambda x: int(x) - 1, input().split())
	F[a].add(b)
	F[b].add(a)
from collections import deque

def bfs():
	ans = 1
	done = set()
	for i in range(N):
		if i in done:
			continue
		queue = deque([i])
		num = 0
		while queue:
			p = queue.popleft()
			for p2 in F[p]:
				if p2 in done:
					continue
				done.add(p2)
				queue.append(p2)
				num += 1
		ans = max(ans, num)
	return ans
print(bfs())


(n, m) = map(int, input().split())
p = [(i, 1) for i in range(n)]

def find(i):
	if p[i][0] == i:
		return i
	else:
		c = find(p[i][0])
		p[i] = (c, 0)
		return c

def union(i, j):
	pi = find(i)
	pj = find(j)
	if not pi == pj:
		if p[pi][1] > p[pj][1]:
			p[pi] = (pi, p[pi][1] + p[pj][1])
			p[pj] = (pi, 0)
		else:
			p[pj] = (pj, p[pi][1] + p[pj][1])
			p[pi] = (pj, 0)
for i in range(m):
	(a, b) = map(int, input().split())
	union(a - 1, b - 1)
ans = 0
for i in range(n):
	if p[i][0] == i:
		ans = max(ans, p[i][1])
print(ans)


(n, m) = map(int, input().split())
par = [-1] * n

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

def union(x, y):
	(x, y) = (find(x), find(y))
	if x != y:
		if x > y:
			(x, y) = (y, x)
		par[x] += par[y]
		par[y] = x
for i in range(m):
	(a, b) = map(int, input().split())
	union(a - 1, b - 1)
print(-min(par))


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())
import sys
sys.setrecursionlimit(10 ** 9)
input = sys.stdin.readline
import sys
sys.setrecursionlimit(10 ** 9)
input = sys.stdin.readline
(n, m) = list(map(int, input().split()))
u = UnionFind(n)
for i in range(m):
	(a, b) = list(map(int, input().split()))
	a -= 1
	b -= 1
	u.unite(a, b)
ans = 0
for i in range(n):
	ans = max(ans, u.size(i))
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
AB = [list(map(int, input().split())) for _ in range(m)]
root = [-1] * n

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

def unity(x, y):
	gx = find(x)
	gy = find(y)
	if gx == gy:
		return
	if root[gx] > root[gy]:
		(gx, gy) = (gy, gx)
	root[gx] += root[gy]
	root[gy] = gx
for (a, b) in AB:
	a -= 1
	b -= 1
	unity(a, b)
print(-min(root))


(N, M) = map(int, input().split())
F = [[] for _ in range(N)]
for i in range(M):
	(A, B) = map(int, input().split())
	A -= 1
	B -= 1
	F[A].append(B)
	F[B].append(A)
a = [1 for _ in range(N)]
l = []
b = [0 for _ in range(N)]
for j in range(N):
	mem = 1
	a[j] = 0
	nex = F[j]
	while True:
		que = nex
		nex = []
		for k in que:
			if a[k] == 1:
				a[k] = 0
				mem += 1
				nex.extend(F[k])
		if nex == []:
			break
	l.append(mem)
print(max(l))


import sys
sys.setrecursionlimit(10 ** 7)
(n, m) = map(int, input().split())
ans = [0 for _ in range(n)]
trees = [[] for _ in range(n)]
for _ in range(m):
	(a, b) = map(int, input().split())
	trees[a - 1].append(b - 1)
	trees[b - 1].append(a - 1)
visited = [False] * n

def dfs(n):
	visited[n] = True
	global temp
	temp += 1
	for i in trees[n]:
		if visited[i]:
			continue
		dfs(i)
ans = 0
for x in range(n):
	if visited[x]:
		continue
	temp = 0
	dfs(x)
	ans = max(temp, ans)
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = map(int, input().split())
f = [[] * (n + 1) for i in range(n + 1)]

def dfs(i):
	searched[i] = 1
	ans = 1
	for j in f[i]:
		if searched[j] == 0:
			ans += dfs(j)
	return ans
for i in range(m):
	(a, b) = map(int, input().split())
	f[a].append(b)
	f[b].append(a)
searched = [0] * (n + 1)
ans = 0
for i in range(1, n + 1):
	if searched[i] == 0:
		ans = max(ans, dfs(i))
print(ans)


from collections import Counter
import math
import statistics
import itertools
(N, M) = list(map(int, input().split()))
par = [i for i in range(1, N + 1)]
rank = [0] * N

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

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

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


from collections import deque
(N, M) = map(int, input().split())
K = [[] for _ in range(N)]
for i in range(M):
	(A, B) = map(int, input().split())
	(A, B) = (A - 1, B - 1)
	K[A].append(B)
	K[B].append(A)
used = [0] * N
ans = 0
for i in range(N):
	c = 0
	if used[i] == 0:
		P = deque([i])
		used[i] = 1
		while P:
			c += 1
			a = P.popleft()
			for j in K[a]:
				if used[j] == 0:
					used[j] = 1
					P.append(j)
	ans = max(c, ans)
print(ans)


(n, m) = map(int, input().split())
parent = [*range(n)]
sz = [1] * n

def anc(a):
	if parent[a] == a:
		return a
	else:
		return anc(parent[a])

def union(a, b):
	pa = anc(a)
	pb = anc(b)
	if sz[pb] < sz[pa]:
		(pa, pb) = (pb, pa)
	parent[pa] = pb
	sz[pb] += sz[pa]
	sz[pa] = 0
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	if anc(a) != anc(b):
		union(a, b)
print(max(sz))


(n, m) = list(map(int, input().split()))
f = [i for i in range(n)]

def find(x):
	if f[x] == x:
		return x
	ret = find(f[x])
	f[x] = ret
	return ret

def union(x, y):
	(i, j) = (find(x), find(y))
	f[max(i, j)] = min(i, j)
for _ in range(m):
	(a, b) = list(map(int, input().split()))
	(a, b) = (a - 1, b - 1)
	union(a, b)
cnt = [0 for _ in range(n)]
for i in range(n):
	cnt[find(i)] += 1
print(max(cnt))


import sys
rln = lambda : next(sys.stdin)
rfs = lambda : rln().split()
ris = lambda : list(map(int, rfs()))
(n, m) = ris()
adj = [[] for _ in range(n)]
for _ in range(m):
	(a, b) = ris()
	(a, b) = (a - 1, b - 1)
	adj[a].append(b)
	adj[b].append(a)
ans = 0
vis = [0] * n
for i in range(n):
	if vis[i]:
		continue
	vis[i] = 1
	k = 0
	stk = [i]
	while stk:
		u = stk.pop()
		k += 1
		for v in adj[u]:
			if vis[v]:
				continue
			vis[v] = 1
			stk.append(v)
	ans = max(ans, k)
print(ans)


from math import gcd
from itertools import combinations, permutations, accumulate, product
from collections import deque, defaultdict, Counter
import decimal
import re
import math
import bisect
import heapq
import sys
sys.setrecursionlimit(10000000)
mod = 10 ** 9 + 7
INF = float('inf')
from sys import stdin
readline = stdin.readline

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

def readTuples():
	return tuple(map(int, readline().split()))

def I():
	return int(readline())

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)]
(n, m) = readInts()
uni = UnionFind(n)
for _ in range(m):
	(a, b) = readInts()
	a -= 1
	b -= 1
	uni.union(a, b)
ans = -1
for i in range(n):
	ans = max(ans, uni.size(i))
print(ans)


import sys
sys.setrecursionlimit(10 ** 9)
(n, m) = 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) = map(int, input().split())
	x -= 1
	y -= 1
	unite(x, y)
print(-min(root))


from collections import Counter
(N, M) = map(int, input().split())
AB = [map(int, input().split()) for _ in range(M)]
F = list(range(N + 1))
for (A, B) in AB:
	H = []
	while F[A] != A:
		H.append(A)
		A = F[A]
	while F[B] != B:
		H.append(B)
		B = F[B]
	for h in H + [B]:
		F[h] = A
for (i, f) in enumerate(F):
	H = [i]
	while F[f] != f:
		H.append(f)
		f = F[f]
	for h in H:
		F[h] = f
print(Counter(F).most_common(1)[0][1])


class UnionFind:

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

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

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x == y:
			return
		if self.rank[x] > self.rank[y]:
			self.par[y] = x
			self.siz[x] += self.siz[y]
		else:
			self.par[x] = y
			self.siz[y] += self.siz[x]
			if self.rank[x] == self.rank[y]:
				self.rank[y] += 1

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

	def size(self, x):
		return self.siz[self.find(x)]
(n, m) = map(int, input().split())
uf = UnionFind(n)
for i in range(m):
	(a, b) = map(int, input().split())
	a -= 1
	b -= 1
	uf.unite(a, b)
res = 0
for i in range(n):
	res = max(res, uf.size(i))
print(res)


class UnionFind:

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

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

	def unite(self, x, y):
		x = self.find(x)
		y = self.find(y)
		if x != y:
			if self.rank[x] < self.rank[y]:
				self.parent[x] = y
				self.size[y] += self.size[x]
			else:
				self.parent[y] = x
				self.size[x] += self.size[y]
				if self.rank[x] == self.rank[y]:
					self.rank[x] += 1

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

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

	def group_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.parent) if i == x]

	def group_count(self):
		return len(self.roots())

	def all_group_members(self):
		return {r: self.group_members(r) for r in self.roots()}

	def __str__(self):
		return '\n'.join(('{}: {}'.format(r, self.group_members(r)) for r in self.roots()))
(n, m) = map(int, input().split())
uf = UnionFind(n + 1)
for _ in range(m):
	(a, b) = map(int, input().split())
	uf.unite(a, b)
print(max(uf.size))