Problem:
Score : 400 points

Problem Statement

There are N persons called Person 1 through Person N.

You are given M facts that "Person A_i and Person B_i are friends." The same fact may be given multiple times.

If X and Y are friends, and Y and Z are friends, then X and Z are also friends. There is no friendship that cannot be derived from the M given facts.

Takahashi the evil wants to divide the N persons into some number of groups so that every person has no friend in his/her group.

At least how many groups does he need to make?

Constraints

2 \leq N \leq 2\times 10^5

0 \leq M \leq 2\times 10^5

1\leq A_i,B_i\leq N

A_i \neq B_i

Input

Input is given from Standard Input in the following format:

N M
A_1 B_1
\vdots
A_M B_M

Output

Print the answer.

Sample Input 1

5 3
1 2
3 4
5 1

Sample Output 1

3

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

Sample Input 2

4 10
1 2
2 1
1 2
2 1
1 2
1 3
1 4
2 3
2 4
3 4

Sample Output 2

4

Sample Input 3

10 4
3 1
4 1
5 9
2 6

Sample Output 3

3

Solution in Go (1.14.1) (judge verdict: Accepted)

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

var scanner = bufio.NewScanner(os.Stdin)

func NextStr() string {
	scanner.Scan()
	return scanner.Text()
}

func NextInt() int {
	i, _ := strconv.Atoi(NextStr())
	return i
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

type UnionFind struct {
	roots []int
	sizes []int
	ranks []int
}

func NewUnionFind(n int) UnionFind {
	roots := make([]int, n)
	sizes := make([]int, n)
	ranks := make([]int, n)
	for i := 0; i < n; i++ {
		roots[i] = i
		sizes[i] = 1
		ranks[i] = 1
	}
	return UnionFind{roots, sizes, ranks}
}

func (u *UnionFind) Root(x int) int {
	if u.roots[x] == x {
		return x
	}
	u.roots[x] = u.Root(u.roots[x])
	return u.roots[x]
}

func (u *UnionFind) Unite(x, y int) {
	if u.Same(x, y) {
		return
	}

	x = u.Root(x)
	y = u.Root(y)

	if u.Rank(x) > u.Rank(y) {
		x, y = y, x
	}

	u.sizes[x] += u.Size(y)

	u.roots[y] = x
	if u.Rank(x) == u.Rank(y) {
		u.ranks[x]++
	}
}

func (u *UnionFind) Rank(x int) int {
	return u.ranks[u.Root(x)]
}

func (u *UnionFind) Size(x int) int {
	return u.sizes[u.Root(x)]
}

func (u *UnionFind) Same(x, y int) bool {
	if u.Root(x) == u.Root(y) {
		return true
	}
	return false
}

func main() {
	scanner.Split(bufio.ScanWords)
	n, m := NextInt(), NextInt()
	u := NewUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := NextInt()-1, NextInt()-1
		u.Unite(a, b)
	}
	var ans int

	for i := 0; i < n; i++ {
		ans = max(ans, u.Size(i))
	}
	fmt.Println(ans)
}