import Control.Applicative
import Control.Monad
import Control.Monad.State
import Data.Array.IO

data DisjointSet = DS { parent :: Int
                      , child :: [Int]
                      , rank :: Int
                      } deriving (Show)

type DisjointForest = IOArray Int DisjointSet

main = do
        [n,q] <- map read.words<$>getLine
        qs <- replicateM q $ map read.words<$>getLine
        dsf <- newListArray (0,n-1) $ map (\x -> DS x [] 0) [0..n-1]
        execStateT (sequence_ $ map inpToQuery qs) dsf

inpToQuery [c,x,y]
    | c == 0 = unite x y
    | c == 1 = same x y

modifyArray :: Ix i => IOArray i a -> i -> (a -> a) -> IO ()
modifyArray arr ix f = do
        e <- readArray arr ix
        writeArray arr ix (f e)

addRank :: DisjointForest -> Int -> IO ()
addRank arr x = do
        childs <- child<$>readArray arr x
        case childs of
            [] -> modifyArray arr x (\a -> a {rank = rank a + 1})
            _  -> do
                          modifyArray arr x (\a -> a {rank = rank a + 1})
                          mapM_ (addRank arr) childs

makeSet :: Int -> StateT DisjointForest IO ()
makeSet x = get >>= \arr -> liftIO $ modifyArray arr x (\_ -> DS x [] 0)


findSet :: Int -> StateT DisjointForest IO Int
findSet x = do
        f <- get
        x' <- liftIO $ parent<$>readArray f x
        if x == x' then return x
                   else findSet x'

union :: Int -> Int -> StateT DisjointForest IO ()
union x y = do
        f <- get
        liftIO $ modifyArray f x (\ds -> ds {parent = y})
        liftIO $ modifyArray f y (\ds -> ds {child = x : child ds})

same :: Int -> Int -> StateT DisjointForest IO ()
same x y = do
        x' <- findSet x
        y' <- findSet y
        f <- get
        acc <- liftIO $ getAssocs f
        if x' == y' then liftIO $ putStrLn "1"
                    else liftIO $ putStrLn "0"

unite :: Int -> Int -> StateT DisjointForest IO ()
unite x y = do
        x' <- findSet x
        y' <- findSet y
        union x' y'