import Data.List
import Data.Function

data Node = Node Int deriving (Show, Eq, Ord)
type Edge = (Node, Node)
-- Forward or Backward
data Direction = F | B deriving (Show, Eq, Ord)

getId :: Node -> Int
getId (Node i) = i

getNodes :: Int -> [Edge] -> [Node]
getNodes n edges = sort $ map snd . filter (\(s,e) -> getId s == n) $ edges

-- rootNode = Node 1
-- sampleEdges = [(Node 1, Node 2), (Node 2, Node 4), (Node 2, Node 5), (Node 4, Node 3)]
-- sampleEdges = [(Node 1, Node 2), (Node 1, Node 3), (Node 2, Node 3), (Node 2, Node 4), (Node 3, Node 5), (Node 4, Node 6), (Node 5, Node 6)]

visit :: Node -> [Edge] -> [(Int, Direction)] -> [(Int, Direction)]
visit node edges result
  | visited node result = result
  | otherwise           = let nodeId        = getId node
                              start         = (nodeId, F)  : result
                              back          = foldl (goDepth edges) start (getNodes nodeId edges)
                              end           = (nodeId, B) : back
                              goDepth es    = \x y -> visit y es x
                          in end

visited :: Node -> [(Int, Direction)] -> Bool
visited (Node i) result = i `elem` (map fst result)

format :: [(Int, Direction)] -> [String]
format result = map toStr . groupBy gf . sortBy sf . zip [1..] . reverse $ result
  where sf (_, e1) (_, e2)                   = compare e1 e2
        gf (_, (i1, _)) (_, (i2, _))         = i1 == i2
        toStr [(t1, (i1, F)), (t2, (i2, B))] = show i1 ++ " " ++ show t1 ++ " " ++ show t2

parseEdge :: [String] -> [Edge]
parseEdge (s:_:xs) = map (\e -> (Node (read s), Node (read e))) xs

main = do
  getLine
  inputs <- fmap (map words . lines) $ getContents
  let edges = concatMap parseEdge inputs
  mapM_ putStrLn (format $ visit (Node 1) edges [])