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 Haskell (GHC 8.8.3) (judge verdict: Accepted)

module Main where

import qualified Data.Vector.Unboxed.Mutable   as VUM
import qualified Data.Vector.Unboxed           as VU
import           Control.Monad.Primitive
import qualified Data.ByteString.Char8         as BS
import qualified Data.ByteString.Lazy.Char8    as BSL
import qualified Data.ByteString.Builder       as BSB
import           Data.Char                      ( isSpace )
import           Data.List                      ( unfoldr )


main :: IO ()
main = do
  [n, m] <- unfoldr (BS.readInt . BS.dropWhile isSpace) <$> BS.getLine
  pairs <- VU.replicateM m $ (\v -> (v VU.! 0 - 1, v VU.! 1 - 1)) . VU.unfoldr (BS.readInt . BS.dropWhile isSpace) <$> BS.getLine
  uf <- initUf n
  uf' <- VU.foldM (\uf (a, b) -> uniteUf uf a b) uf pairs
  sizes <- mapM (sizeUf uf') [0..n-1]
  print $ maximum sizes

data UnionFind s = UnionFind
  { parent :: VUM.MVector s Int
  , size :: VUM.MVector s Int
  }

-- Vector internally uses 0-indexed

initUf :: PrimMonad m => Int -> m (UnionFind (PrimState m))
initUf n = UnionFind <$> VU.thaw (VU.enumFromN 0 n) <*> VUM.replicate n 1

rootUf
  :: PrimMonad m
  => UnionFind (PrimState m)
  -> Int
  -> m (UnionFind (PrimState m), Int)
rootUf uf x = do
  px <- VUM.read (parent uf) x
  if px == x
    then return (uf, x)
    else do
      (UnionFind parent' size', rx) <- rootUf uf px
      VUM.write parent' x rx
      return (UnionFind parent' size', rx)

sameUf
  :: PrimMonad m
  => UnionFind (PrimState m)
  -> Int
  -> Int
  -> m (UnionFind (PrimState m), Bool)
sameUf uf x y = do
  (uf' , rx) <- rootUf uf x
  (uf'', ry) <- rootUf uf' y
  return (uf'', rx == ry)

uniteUf
  :: PrimMonad m
  => UnionFind (PrimState m)
  -> Int
  -> Int
  -> m (UnionFind (PrimState m))
uniteUf uf x y = do
  (uf'                           , x') <- rootUf uf x
  (uf''@(UnionFind parent' size'), y') <- rootUf uf' y
  if x' == y'
    then return uf''
    else do
      sizeX <- VUM.read size' x'
      sizeY <- VUM.read size' y'
      if sizeX < sizeY
        then do
          VUM.write parent' x' y'
          VUM.write size' y' (sizeX + sizeY)
          return $ UnionFind parent' size'
        else do
          VUM.write parent' y' x'
          VUM.write size' x' (sizeX + sizeY)
          return $ UnionFind parent' size'

sizeUf :: PrimMonad m => UnionFind (PrimState m) -> Int -> m Int
sizeUf uf x = do
  (UnionFind _ size', x') <- rootUf uf x
  VUM.read size' x'