{-# LANGUAGE BangPatterns, OverloadedStrings #-}

import Control.Monad
import Control.Monad.ST
import Data.Array.Unboxed
import Data.Array.ST
import Data.Bits
import Data.Bool
import Data.Char
import Data.Coerce
import Data.Function
import Data.Int 
import Data.IORef
import Data.List
import Data.Maybe
import qualified Data.Map.Strict as M
import qualified Data.Vector.Unboxed as V
import qualified Data.Vector.Unboxed.Mutable as MV
import qualified Data.ByteString.Char8 as BS

main :: IO ()
main = do
  (n, m) <- getIntPair
  ps <- replicateM m getIntPair
  print $ solve n ps

solve :: Int -> [(Int, Int)] -> Int
solve n ps = runST $ do
  t <- newUF (1, n)
  forM_ ps $ uncurry (uniteUF t)
  maximum <$> forM [1..n] (sizeUF t)


-- Input

getInt :: IO Int
getInt = readLn
second :: (b -> c) -> (a, b) -> (a, c)
second f (a, b) = (a, f b)

readInt :: BS.ByteString -> Maybe (Int, BS.ByteString)
readInt = fmap (second BS.tail) . BS.readInt

getIntVec :: Int -> IO (V.Vector Int)
getIntVec n = V.unfoldrN n readInt <$> BS.getLine
 
getIntList :: IO [Int]
getIntList = map (fst . fromJust . BS.readInt) . BS.words <$> BS.getLine

getIntegerList :: IO [Integer]
getIntegerList = map (fst . fromJust . BS.readInteger) . BS.words <$> BS.getLine

getIntPair :: IO (Int, Int)
getIntPair = do
  v <- getIntVec 2
  return (v V.! 0, v V.! 1)

-- Search

bisearch :: (Int -> Bool) -> (Int, Int) -> (Int, Int)
bisearch check = bis
  where
    bis (l, r)
      | l + 1 == r = (l, r)
      | check mid  = bis (mid, r)
      | otherwise  = bis (l, mid)
      where
        mid = l + (r - l) `div` 2

-- Modular Arithmetic
--
 
modulo :: Int64
modulo = 10^9+7
addMod, subMod, mulMod :: Int64 -> Int64 -> Int64
addMod !x !y | x + y >= modulo = x + y - modulo
             | otherwise = x + y
subMod !x !y | x >= y = x - y
             | otherwise = x - y + modulo
mulMod !x !y = (x * y) `rem` modulo

newtype N = N { unwrapN :: Int64 } deriving (Eq)
instance Show N where
  show (N x) = show x
instance Num N where
  (+) = coerce addMod
  (-) = coerce subMod
  (*) = coerce mulMod
  fromInteger n = N (fromInteger (n `mod` fromIntegral modulo))
  abs = undefined; signum = undefined
---
 
exEuclid :: (Eq a, Integral a) => a -> a -> (a, a, a)
exEuclid !f !g = loop 1 0 0 1 f g
  where loop !u0 !u1 !v0 !v1 !f 0 = (f, u0, v0)
        loop !u0 !u1 !v0 !v1 !f g =
          case divMod f g of
            (q,r) -> loop u1 (u0 - q * u1) v1 (v0 - q * v1) g r
 
recipM :: Int64 -> Int64
recipM !x = case exEuclid x modulo of
             (1,a,_) -> a `mod` modulo
             (-1,a,_) -> (-a) `mod` modulo
divM :: Int64 -> Int64 -> Int64
divM !x !y = x `mulMod` recipM y
 
instance Fractional N where
  (/) = coerce divM
  recip = coerce recipM
  fromRational = undefined

-- 組み合わせ
powerset :: [a] -> [[a]]  
powerset xs = filterM (\x -> [True, False]) xs

-- Union-Find木
newtype UFind s = UFind (STUArray s Int Int)

newUF :: (Int, Int) -> ST s (UFind s)
newUF (i, j) = liftM UFind (newListArray (i, j) (repeat (-1)))

rootUF :: UFind s -> Int -> ST s Int
rootUF (UFind a) i = do
  p <- readArray a i
  if p < 0
    then return i
    else do
      rp <- rootUF (UFind a) p
  　   writeArray a i rp
      return rp

findUF :: UFind s -> Int -> Int -> ST s Bool
findUF uf x y = liftM2 (==) (rootUF uf x) (rootUF uf y)

uniteUF :: UFind s -> Int -> Int -> ST s ()
uniteUF uf@(UFind a) x y = do
  rx <- rootUF uf x
  ry <- rootUF uf y
  when (rx /= ry) $ do
    sx <- readArray a rx
    sy <- readArray a ry
    writeArray a rx (sx + sy)
    writeArray a ry rx

sizeUF :: UFind s -> Int -> ST s Int
sizeUF uf@(UFind a) n = negate <$> (readArray a =<< (rootUF uf n))


Measured memory_bytes: 86652