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 proconio::input;
use proconio::marker::Usize1;
use std::cmp::Ordering;

enum ParRank {
    Parent(usize),
    Rank(usize),
}

struct UnionFind {
    v: Vec<ParRank>,
}

impl UnionFind {
    fn new(n: usize) -> UnionFind {
        let mut v = Vec::new();
        for _ in 0..n {
            v.push(ParRank::Rank(1));
        }
        UnionFind { v }
    }

    fn root(&self, i: usize) -> usize {
        match self.v[i] {
            ParRank::Rank(_) => i,
            ParRank::Parent(j) => {
                let r = self.root(j);
                // self.v[i] = ParRank::Parent(r);
                r
            }
        }
    }

    fn size(&self, i: usize) -> usize {
        if let ParRank::Rank(r) = self.v[self.root(i)] {
            r
        } else {
            panic!("UnionFind: root is not root");
        }
    }

    fn unite(&mut self, i1: usize, i2: usize) -> bool {
        let r1 = self.root(i1);
        let r2 = self.root(i2);
        if r1 == r2 {
            return false;
        }
        let rank1 = if let ParRank::Rank(r) = self.v[r1] { r } else {
            panic!("UnionFind: root is not root");
        };
        let rank2 = if let ParRank::Rank(r) = self.v[r2] { r } else {
            panic!("UnionFind: root is not root");
        };
        match self.size(r1).cmp(&self.size(r2)) {
            Ordering::Less => {
                self.v[r1] = ParRank::Parent(r2);
                self.v[r2] = ParRank::Rank(rank1 + rank2);
            },
            Ordering::Equal => {
                self.v[r1] = ParRank::Parent(r2);
                self.v[r2] = ParRank::Rank(rank1 + rank2);
            },
            Ordering::Greater => {
                self.v[r2] = ParRank::Parent(r1);
                self.v[r1] = ParRank::Rank(rank1 + rank2);
            },
        }
        return true;
    }
}

fn main() {
    input! {
        nm: (usize, usize),
        ab: [(Usize1, Usize1); nm.1],
    };
    let n = nm.0;
    let m = nm.1;
    let a: Vec<usize> = ab.iter().map(|(a,_)| *a).collect();
    let b: Vec<usize> = ab.iter().map(|(_,b)| *b).collect();
    let mut uf = UnionFind::new(n);
    for (a, b) in ab {
        uf.unite(a, b);
    }
    let size = (0..n).map(|i| uf.size(i)).max().unwrap();
    println!("{}", size);
}