import Control.Monad.State.Strict
import Data.Bool
import qualified Data.ByteString.Char8 as C
import Data.Coerce
import qualified Data.IntMap as M
import Data.Tuple
import Data.Vector.Generic ((!))
import qualified Data.Vector as V
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Unboxed as U

main = sol <$> gett >>= print

gett = U.unfoldr (runStateT $ (,) <$> geti <*> geti) <$> C.getContents

geti = coerce $ C.readInt . C.dropWhile (<'0') :: StateT C.ByteString Maybe Int

sol v = pred . fst $ lowlink 0 1 M.empty
  where
  n = fst $ U.head v
  g = V.accumulate (flip (:)) (V.replicate (n+1) [])
    $ V.concatMap (V.fromList . liftM2 (:) swap return)
    $ (G.convert :: U.Vector (Int, Int) -> V.Vector (Int,Int)) $ U.tail v
  lowlink s t low = (c', low')
    where
    (c,low') = foldr f (0, M.insert t (M.size low) low) $ g!t
    c' = c + bool 0 1 (M.size low==low' M.! t)
    f i (c,low)
      | i == s          = (c,low)
      | M.member i low  = (c,M.adjust (min (low M.! i)) t low)
      | otherwise       = (c+c',M.adjust (min (low' M.! i)) t low')
      where
      (c',low') = lowlink t i low