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: Accepted)

use std::collections::*;
use std::io::*;
use std::*;
// template {{{
macro_rules! get {
    ($($t:tt),*; $n:expr) => {
        {
            let stdin = std::io::stdin();
            let ret = std::io::BufRead::lines(stdin.lock()).take($n).map(|line| {
                let line = line.unwrap();
                let mut it = line.split_whitespace();
                _get!(it; $($t),*)
            }).collect::<Vec<_>>();
            ret
        }
    };
    ($($t:tt),*) => {
        {
            let mut line = String::new();
            std::io::stdin().read_line(&mut line).unwrap();
            let mut it = line.split_whitespace();
            _get!(it; $($t),*)
        }
    };
}
macro_rules! _get {
    ($it:ident; [char]) => {
        _get!($it; String).chars().collect::<Vec<_>>()
    };
    ($it:ident; [u8]) => {
        _get!($it; String).bytes().collect::<Vec<_>>()
    };
    ($it:ident; usize1) => {
        $it.next().unwrap().parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1
    };
    ($it:ident; [usize1]) => {
        $it.map(|s| s.parse::<usize>().unwrap_or_else(|e| panic!("{}", e)) - 1).collect::<Vec<_>>()
    };
    ($it:ident; [$t:ty]) => {
        $it.map(|s| s.parse::<$t>().unwrap_or_else(|e| panic!("{}", e))).collect::<Vec<_>>()
    };
    ($it:ident; $t:ty) => {
        $it.next().unwrap().parse::<$t>().unwrap_or_else(|e| panic!("{}", e))
    };
    ($it:ident; $($t:tt),+) => {
        ($(_get!($it; $t)),*)
    };
}
mod unionfind {
    pub struct Unionfind {
        par: Vec<i32>,
        group_count: usize,
    }
    impl Unionfind {
        pub fn new(n: usize) -> Self {
            Unionfind {
                par: vec![-1; n as usize],
                group_count: n as usize,
            }
        }
        fn find_root(&mut self, mut x: usize) -> usize {
            while self.par[x] >= 0 {
                x = self.par[x] as usize;
            }
            x
        }
        pub fn unite(&mut self, x: usize, y: usize) {
            let mut rx = self.find_root(x);
            let mut ry = self.find_root(y);
            if rx == ry {
                return;
            }
            if self.par[rx] > self.par[ry] {
                std::mem::swap(&mut rx, &mut ry);
            }
            self.par[rx] += self.par[ry];
            self.par[ry] = rx as i32;
            self.group_count -= 1;
        }
        pub fn is_same_group(&mut self, x: usize, y: usize) -> bool {
            self.find_root(x) == self.find_root(y)
        }
        pub fn get_group_size(&mut self, x: usize) -> usize {
            let rx = self.find_root(x);
            (-self.par[rx]) as usize
        }
        pub fn get_num_of_groups(&self) -> usize {
            self.group_count
        }
    }
}
// }}}
type UF = unionfind::Unionfind;

fn main() {
    let (n, m) = get!(usize, usize);
    let input = get!(usize1, usize1; m);
    let mut uf = UF::new(n);
    for i in 0..m {
        uf.unite(input[i].0, input[i].1);
    }
    let mut ans = 0;
    for i in 0..n {
        ans = ans.max(uf.get_group_size(i));
    }
    println!("{}", ans);
}