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 Rust (1.42.0) (judge verdict: Wrong Answer)

/// input macro from https://qiita.com/tanakh/items/1ba42c7ca36cd29d0ac8
macro_rules ! read_value {($ next : expr , ($ ($ t : tt ) ,* ) ) => {($ (read_value ! ($ next , $ t ) ) ,* ) } ; ($ next : expr , [$ t : tt ; $ len : expr ] ) => {(0 ..$ len ) . map (| _ | read_value ! ($ next , $ t ) ) . collect ::< Vec < _ >> () } ; ($ next : expr , chars ) => {read_value ! ($ next , String ) . chars () . collect ::< Vec < char >> () } ; ($ next : expr , usize1 ) => {read_value ! ($ next , usize ) - 1 } ; ($ next : expr , $ t : ty ) => {$ next () . parse ::<$ t > () . expect ("Parse error" ) } ; }
macro_rules ! input_inner {($ next : expr ) => {} ; ($ next : expr , ) => {} ; ($ next : expr , $ var : ident : $ t : tt $ ($ r : tt ) * ) => {let $ var = read_value ! ($ next , $ t ) ; input_inner ! {$ next $ ($ r ) * } } ; }
macro_rules ! input {(source = $ s : expr , $ ($ r : tt ) * ) => {let mut iter = $ s . split_whitespace () ; let mut next = || {iter . next () . unwrap () } ; input_inner ! {next , $ ($ r ) * } } ; ($ ($ r : tt ) * ) => {let stdin = std :: io :: stdin () ; let mut bytes = std :: io :: Read :: bytes (std :: io :: BufReader :: new (stdin . lock () ) ) ; let mut next = move || -> String {bytes . by_ref () . map (| r | r . unwrap () as char ) . skip_while (| c | c . is_whitespace () ) . take_while (| c |! c . is_whitespace () ) . collect () } ; input_inner ! {next , $ ($ r ) * } } ; }
macro_rules ! rough_print {($ x : expr $ (, $ s : expr ) * ) => {print ! ("{:?}" , $ x ) ; $ (print ! (", {:?}" , $ s ) ; ) * println ! ("" ) ; } ; }

struct UnionFind<T>
where
    T: Clone + Eq + std::hash::Hash,
{
    map:  std::collections::HashMap<T, usize>,
    par:  Vec<T>,
    rank: Vec<usize>,
}
impl<T> UnionFind<T>
where
    T: Clone + Eq + std::hash::Hash,
{
    fn new(init: Vec<T>) -> Self {
        let len = init.len();
        let mut map = std::collections::HashMap::new();
        for (i, v) in init.iter().enumerate() {
            map.insert(v.clone(), i);
        }
        Self {
            map:  map,
            par:  init,
            rank: vec![0; len],
        }
    }

    fn find(&mut self, i: T) -> T {
        let i_ind = {
            if let Some(&ind) = self.map.get(&i) {
                ind
            }
            else {
                panic!("The value can't be found. [in find of UnionFind]");
            }
        };
        if i == self.par[i_ind] {
            return i;
        }
        else {
            let par = self.par[i_ind].clone();
            let tmp = self.find(par);
            self.par[i_ind] = tmp.clone();
            return tmp;
        }
    }

    #[inline]
    fn same(&mut self, i: T, j: T) -> bool { self.find(i) == self.find(j) }

    fn unite(&mut self, i: T, j: T) {
        let i_par = self.find(i);
        let j_par = self.find(j);
        let i_par_ind = {
            if let Some(&ind) = self.map.get(&i_par) {
                ind
            }
            else {
                panic!("The value can't be found. [in unite of UnionFind]");
            }
        };
        let j_par_ind = {
            if let Some(&ind) = self.map.get(&j_par) {
                ind
            }
            else {
                panic!("The value can't be found. [in unite of UnionFind]");
            }
        };
        if self.rank[i_par_ind] > self.rank[j_par_ind] {
            self.par[j_par_ind] = i_par;
        }
        else {
            self.par[i_par_ind] = j_par;
            if self.rank[i_par_ind] == self.rank[j_par_ind] {
                self.rank[j_par_ind] += 1;
            }
        }
    }
}
fn solve() {
    input!(n: usize, m: usize, a: [(usize1, usize1); m]);
    let mut uf = UnionFind::new((0..n).collect());

    for (i, j) in a {
        uf.unite(i, j);
    }

    let mut counter = vec![0; n];
    for i in 0..n {
        counter[uf.par[i]] += 1;
    }

    rough_print!(counter.iter().max().unwrap());
}

fn main() {
    std::thread::Builder::new()
        .name("solve".into())
        .stack_size(256 * 1024 * 1024)
        .spawn(solve)
        .unwrap()
        .join()
        .unwrap();
}