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)

// This code is generated by [cargo-atcoder](https://github.com/tanakh/cargo-atcoder)
// Original source code:
/*
#![allow(unused_imports)]
use proconio::input;
use proconio::marker::*;
use std::collections::BTreeMap;

pub struct UnionFind(Vec<usize>);

impl UnionFind {
    pub fn new(n: usize) -> UnionFind {
        UnionFind((0..n).collect())
    }

    pub fn find(&mut self, i: usize) -> usize {
        if self.0[i] == i {
            i
        } else {
            let p = self.0[i];
            self.0[i] = self.find(p);
            self.0[i]
        }
    }

    pub fn union(&mut self, i: usize, j: usize) {
        let ni = self.find(i);
        let nj = self.find(j);
        self.0[ni] = nj;
    }
}
fn main() {
    input!(n: usize, m: usize);
    let mut uf = UnionFind::new(n);
    for _ in 0..m {
        input!(a: Usize1, b: Usize1);
        uf.union(a, b);
    }
    let mut cnt: BTreeMap<usize, usize> = BTreeMap::new();
    // flatten
    for i in 0..n {
        uf.find(i);
    }
    for i in 0..n {
        let r = uf.find(i);
        cnt.entry(r).and_modify(|e| *e += 1).or_insert(1);
    }
    let mut max = 0;
    for (_, &tmp) in cnt.iter() {
        max = std::cmp::max(tmp, max);
    }

    println!("{}", max);
}
*/

fn main() {
    let exe = "/tmp/binE85DCEBA";
    std::io::Write::write_all(&mut std::fs::File::create(exe).unwrap(), &decode(BIN)).unwrap();
    std::fs::set_permissions(exe, std::os::unix::fs::PermissionsExt::from_mode(0o755)).unwrap();
    std::process::exit(std::process::Command::new(exe).status().unwrap().code().unwrap())
}

fn decode(v: &str) -> Vec<u8> {
    let mut ret = vec![];
    let mut buf = 0;
    let mut tbl = vec![64; 256];
    for i in 0..64 { tbl[TBL[i] as usize] = i as u8; }
    for (i, c) in v.bytes().filter_map(|c| { let c = tbl[c as usize]; if c < 64 { Some(c) } else { None } }).enumerate() {
        match i % 4 {
            0 => buf = c << 2,
            1 => { ret.push(buf | c >> 4); buf = c << 4; }
            2 => { ret.push(buf | c >> 2); buf = c << 6; }
            3 => ret.push(buf | c),
            _ => unreachable!(),
        }
    }
    ret
}

const TBL: &'static [u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const BIN: &'static str = "<base64-encoded ELF executable removed>";