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 C# (Mono-mcs 6.8.0.105) (judge verdict: Accepted)

using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{
	//Main
	static void Main(string[] args)
	{
		//読み込む
		string[] S = Console.ReadLine().Split(' ');
		int N = int.Parse(S[0]);
		int M = int.Parse(S[1]);

		//union find木
		UnionFind groupTree = new UnionFind(N);

		//読み込む
		for(int i=0; i<M; i++){
				string[] line = Console.ReadLine().Split(' ');
				int A = int.Parse(line[0])-1;
				int B = int.Parse(line[1])-1;

				//UnionFindに組み込む
				groupTree.Merge(A,B);
		}


		//特定のグループの人数を格納
		/*
		根っことして有り得るのは0 ~ Nのどれか
		*/
		int[] groupNum = new int[N];

		for(int i=0; i<N; i++){
			//根っこを取得
			int root = groupTree.Root(i);
			//debug
			//Console.WriteLine("i={0}, root={1}",i,root);
			
			groupNum[root] ++;
		}

		//結局、一番人数の多いグループの構成員と同じだけに分ける必要
		int ans = groupNum.Max();
		Console.WriteLine(ans);
	}
}



//自作クラス
//ジェネリック（タイプを指定可能）ではなく、取り敢えずintに限定して作成
class UnionFind
{
		public readonly int[] Array;

		public UnionFind(int capacity)
		{
				this.Array = new int[capacity];

				//自身を根として初期化
				for(int i=0; i<capacity; i++){
						this.Array[i] = i;
				}
		}

		//unionFindへの追加（インデックスaとインデックスbの根を同一にする）
		public void Merge(int a, int b){
			//根を決定
			int rootA = Root(a);
			int rootB = Root(b);
			int newRoot = Math.Min(rootA, rootB);

			//より小さい方に根を変化させる
			this.Array[rootA] = newRoot;
			this.Array[rootB] = newRoot;
		}

		//根を判定し、出力
		public int Root(int ind){
			int root = 0;

			if(this.Array[ind] == ind){
					root = ind;
			}else{
					root = Root(this.Array[ind]);
			}

			//根をその場で更新しつつ、出力もする（一種のメモ化再帰とも）
			return this.Array[ind] = root;
		}

		//2つのインデックスの根が同一なら、trueを返す
		public bool SameRoot(int a, int b){
			return this.Root(a) == this.Root(b);
		}
}