Kris works in a large company "Blake Technologies". As a best engineer of the company he was assigned a task to develop a printer that will be able to print horizontal and vertical strips. First prototype is already built and Kris wants to tests it. He wants you to implement the program that checks the result of the printing.Printer works with a rectangular sheet of paper of size n × m. Consider the list as a table consisting of n rows and m columns. Rows are numbered from top to bottom with integers from 1 to n, while columns are numbered from left to right with integers from 1 to m. Initially, all cells are painted in color 0.Your program has to support two operations:   Paint all cells in row ri in color ai;  Paint all cells in column ci in color ai. If during some operation i there is a cell that have already been painted, the color of this cell also changes to ai.Your program has to print the resulting table after k operation.

The first line of the input contains three integers n, m and k (1  ≤  n,  m  ≤ 5000, n·m ≤ 100 000, 1 ≤ k ≤ 100 000) — the dimensions of the sheet and the number of operations, respectively. Each of the next k lines contains the description of exactly one query:    1 ri ai (1 ≤ ri ≤ n, 1 ≤ ai ≤ 109), means that row ri is painted in color ai;  2 ci ai (1 ≤ ci ≤ m, 1 ≤ ai ≤ 109), means that column ci is painted in color ai.

Print n lines containing m integers each — the resulting table after all operations are applied.

NoteThe figure below shows all three operations for the first sample step by step. The cells that were painted on the corresponding step are marked gray.

import Data.List(sort,sortBy,intersect)

-- |  The 'isSorted' predicate returns 'True' if the elements of a list occur
-- in non-descending order,  equivalent to @'isSortedBy' ('<=')@.
isSorted :: Ord a => [a] -> Bool
isSorted = isSortedBy (<=)

-- |  The 'isSortedBy' function returns 'True' iff the predicate returns true
-- for all adjacent pairs of elements in the list.
isSortedBy :: (a -> a -> Bool) -> [a] -> Bool
isSortedBy lte = loop
  where
    loop []       = True
    loop [_]      = True
    loop (x:y:zs) = (x `lte` y) && loop (y:zs)

-- |  The 'member' function returns 'True' if the element appears in the
-- ordered list.
member :: Ord a => a -> [a] -> Bool
member = memberBy compare

-- |  The 'memberBy' function is the non-overloaded version of 'member'.
memberBy :: (a -> a -> Ordering) -> a -> [a] -> Bool
memberBy cmp x = loop
  where
    loop []     = False
    loop (y:ys) = case cmp x y of
                    LT -> False
                    EQ -> True
                    GT -> loop ys

-- |  The 'has' function returns 'True' if the element appears in the list;
-- it is equivalent to 'member' except the order of the arguments is reversed,
-- making it a function from an ordered list to its characteristic function.
has :: Ord a => [a] -> a -> Bool
has xs y = memberBy compare y xs

-- |  The 'hasBy' function is the non-overloaded version of 'has'.
hasBy :: (a -> a -> Ordering) -> [a] -> a -> Bool
hasBy cmp xs y = memberBy cmp y xs

-- |  The 'insertBag' function inserts an element into a list.  If the element
-- is already there,  then another copy of the element is inserted.
insertBag :: Ord a => a -> [a] -> [a]
insertBag = insertBagBy compare

-- |  The 'insertBagBy' function is the non-overloaded version of 'insertBag'.
insertBagBy :: (a -> a -> Ordering) -> a -> [a] -> [a]
insertBagBy cmp = loop
  where
    loop x [] = [x]
    loop x (y:ys)
      = case cmp x y of
         GT -> y:loop x ys
         _  -> x:y:ys

-- |  The 'insertSet' function inserts an element into an ordered list.
-- If the element is already there,  then the element replaces the existing
-- element.
insertSet :: Ord a => a -> [a] -> [a]
insertSet = insertSetBy compare

-- |  The 'insertSetBy' function is the non-overloaded version of 'insertSet'.
insertSetBy :: (a -> a -> Ordering) -> a -> [a] -> [a]
insertSetBy cmp = loop
  where
    loop x [] = [x]
    loop x (y:ys) = case cmp x y of
            LT -> x:y:ys
            EQ -> x:ys
            GT -> y:loop x ys

{-
-- This function is moderately interesting,  as it encompasses all the
-- "Venn diagram" functions on two sets. (though not merge;  which isn't
-- a set function)

-- However, it doesn't seem that useful,  considering that of the 8 possible
-- functions,  there are only 4 interesting variations:  isect, union, minus,
-- and xunion.  Due to interactions with GHC's optimizer,  coded separately,
-- these have a smaller combined object code size than the object code size
-- for genSectBy.  (Or,  turn off certain optimizations and lose speed.)

-- Each individual object code can be recovered from genSectBy via GHC's
-- inliner and constant propagation;  but this doesn't save much in terms
-- of source code size and reduces portability.

-- Note that the Static Argument Transformation is necessary for this to work
-- correctly;  inlining genSectBy allows for cmp and p to be inlined as well,
-- or at least eliminate some indirect jumps.  All of the *By functions in
-- this module follow this idiom for this reason.

genSectBy :: (a -> a -> Ordering)
          -> (Bool -> Bool -> Bool)
          -> [a] -> [a] -> [a]
genSectBy cmp p = loop
  where
    loop [] ys | p False True = ys
               | otherwise    = []
    loop xs [] | p True False = xs
               | otherwise    = []
    loop (x:xs) (y:ys)
      = case cmp x y of
          LT | p True False -> x : loop xs (y:ys)
             | otherwise    ->     loop xs (y:ys)
          EQ | p True True  -> x : loop xs ys
             | otherwise    ->     loop xs ys
          GT | p False True -> y : loop (x:xs) ys
             | otherwise    ->     loop (x:xs) ys

-- Here's another variation that was suggested to me.  It is more general
-- than genSectBy, as it can implement a merge; but it cannot implement
-- a left-biased merge

foldrMergeBy :: (a -> b -> Ordering)
             -> (a -> c -> c) -> (b -> c -> c) -> (a -> b -> c -> c) -> c
             -> [a] -> [b] -> c
foldrMergeBy cmp addA addB unify z = loop
  where
    loop xs [] = foldr addA z xs
    loop [] ys = foldr addB z ys
    loop (x:xs) (y:ys)
      = case cmp x y of
          LT -> x `addA` loop  xs (y:ys)
          EQ -> unify x y (loop xs ys)
          GT -> y `addB` loop (x:xs) ys
-}

-- |  The 'isect' function computes the intersection of two ordered lists.
-- An element occurs in the output as many times as the minimum number of
-- occurrences in either input.  If either input is a set,  then the output
-- is a set.
--
-- > isect [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 3,4 ]
-- > isect [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1, 2,2 ]
isect :: Ord a => [a] -> [a] -> [a]
isect = isectBy compare

-- |  The 'isectBy' function is the non-overloaded version of 'isect'.
isectBy :: (a -> b -> Ordering) -> [a] -> [b] -> [a]
isectBy cmp = loop
  where
     loop [] _ys  = []
     loop _xs []  = []
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT ->     loop xs (y:ys)
          EQ -> x : loop xs ys
          GT ->     loop (x:xs) ys

-- |  The 'union' function computes the union of two ordered lists.
-- An element occurs in the output as many times as the maximum number
-- of occurrences in either input.  The output is a set if and only if
-- both inputs are sets.
--
-- > union [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2, 3,4, 5,6 ]
-- > union [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1,1, 2,2,2 ]
union :: Ord a => [a] -> [a] -> [a]
union = unionBy compare

-- |  The 'unionBy' function is the non-overloaded version of 'union'.
unionBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
unionBy cmp = loop
  where
     loop [] ys = ys
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ -> x : loop xs ys
          GT -> y : loop (x:xs) ys

-- |  The 'minus' function computes the difference of two ordered lists.
-- An element occurs in the output as many times as it occurs in
-- the first input, minus the number of occurrences in the second input.
-- If the first input is a set,  then the output is a set.
--
-- > minus [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2 ]
-- > minus [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 2 ]
minus :: Ord a => [a] -> [a] -> [a]
minus = minusBy compare

-- |  The 'minusBy' function is the non-overloaded version of 'minus'.
minusBy :: (a -> b -> Ordering) -> [a] -> [b] -> [a]
minusBy cmp = loop
  where
     loop [] _ys = []
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ ->     loop xs ys
          GT ->     loop (x:xs) ys

-- |  The 'minus'' function computes the difference of two ordered lists.
-- The result consists of elements from the first list that do not appear
-- in the second list.  If the first input is a set, then the output is
-- a set.
--
-- > minus' [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2 ]
-- > minus' [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == []
-- > minus' [ 1,1, 2,2 ] [ 2 ]          == [ 1,1 ]
minus' :: Ord a => [a] -> [a] -> [a]
minus' = minusBy' compare

-- |  The 'minusBy'' function is the non-overloaded version of 'minus''.
minusBy' :: (a -> b -> Ordering) -> [a] -> [b] -> [a]
minusBy' cmp = loop
  where
     loop [] _ys = []
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ ->     loop xs (y:ys)
          GT ->     loop (x:xs) ys

-- |  The 'xunion' function computes the exclusive union of two ordered lists.
-- An element occurs in the output as many times as the absolute difference
-- between the number of occurrences in the inputs.  If both inputs
-- are sets,  then the output is a set.
--
-- > xunion [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2, 5,6 ]
-- > xunion [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1, 2 ]
xunion :: Ord a => [a] -> [a] -> [a]
xunion = xunionBy compare

-- |  The 'xunionBy' function is the non-overloaded version of 'xunion'.
xunionBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
xunionBy cmp = loop
  where
     loop [] ys = ys
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ ->     loop xs ys
          GT -> y : loop (x:xs) ys

-- |  The 'merge' function combines all elements of two ordered lists.
-- An element occurs in the output as many times as the sum of the
-- occurrences in both lists.   The output is a set if and only if
-- the inputs are disjoint sets.
--
-- > merge [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2,  3,3,4,4,  5,6 ]
-- > merge [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1,1,1,  2,2,2,2,2 ]
merge :: Ord a => [a] -> [a] -> [a]
merge = mergeBy compare

-- |  The 'mergeBy' function is the non-overloaded version of 'merge'.
mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
mergeBy cmp = loop
  where
    loop [] ys  = ys
    loop xs []  = xs
    loop (x:xs) (y:ys)
      = case cmp x y of
         GT -> y : loop (x:xs) ys
         _  -> x : loop xs (y:ys)

-- |  The 'subset' function returns true if the first list is a sub-list
-- of the second.
subset :: Ord a => [a] -> [a] -> Bool
subset = subsetBy compare

-- |  The 'subsetBy' function is the non-overloaded version of 'subset'.
subsetBy :: (a -> a -> Ordering) -> [a] -> [a] -> Bool
subsetBy cmp = loop
  where
    loop [] _ys = True
    loop _xs [] = False
    loop (x:xs) (y:ys)
      = case cmp x y of
         LT -> False
         EQ -> loop xs ys
         GT -> loop (x:xs) ys

{-
-- This is Ian Lynagh's mergesort implementation,  which appeared as
-- Data.List.sort, with the static argument transformation applied.
-- It's not clear whether this modification is truly worthwhile or not.

sort :: Ord a => [a] -> [a]
sort = sortBy compare

sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortBy cmp = foldt (mergeBy cmp) [] . map (\x -> [x])
-}

-- |  The 'sortOn' function provides the decorate-sort-undecorate idiom,
-- also known as the \"Schwartzian transform\".
sortOn :: Ord b => (a -> b) -> [a] -> [a]
sortOn f  = map snd . sortOn' fst .  map (\x -> let y = f x in y `seq` (y, x))

-- |  This variant of 'sortOn' recomputes the sorting key every comparison.
-- This can be better for functions that are cheap to compute.
-- This is definitely better for projections,  as the decorate-sort-undecorate
-- saves nothing and adds two traversals of the list and extra memory
-- allocation.
sortOn' :: Ord b => (a -> b) -> [a] -> [a]
sortOn' f = sortBy (\x y -> compare (f x) (f y))

-- |  The 'nubSort' function is equivalent to @'nub' '.' 'sort'@,  except
-- that duplicates are removed as it sorts. It is essentially the same
-- implementation as @Data.List.sort@, with 'merge' replaced by 'union'.
-- Thus the performance of 'nubSort' should better than or nearly equal
-- to 'sort' alone.  It is faster than both 'sort' and @'nub' '.' 'sort'@
-- when the input contains significant quantities of duplicated elements.
nubSort :: Ord a => [a] -> [a]
nubSort = nubSortBy compare

-- |  The 'nubSortBy' function is the non-overloaded version of 'nubSort'.
nubSortBy :: (a -> a -> Ordering) -> [a] -> [a]
nubSortBy cmp = foldt' (unionBy cmp) [] . runs
  where
    -- 'runs' partitions the input into sublists that are monotonic,
    -- contiguous,  and non-overlapping.   Descending runs are reversed
    -- and adjacent duplicates are eliminated,  so every run returned is
    -- strictly ascending.

    runs (a:b:xs)
      = case cmp a b of
          LT -> asc b (a:) xs
          EQ -> runs (a:xs)
          GT -> desc b [a] xs
    runs xs = [xs]

    desc a as []  = [a:as]
    desc a as (b:bs)
      = case cmp a b of
          LT -> (a:as) : runs (b:bs)
          EQ -> desc a as bs
          GT -> desc b (a:as) bs

    asc a as [] = [as [a]]
    asc a as (b:bs)
      = case cmp a b of
         LT -> asc b (\ys -> as (a:ys)) bs
         EQ -> asc a as bs
         GT -> as [a] : runs (b:bs)

-- |  The 'nubSortOn' function provides decorate-sort-undecorate for 'nubSort'.
nubSortOn :: Ord b => (a -> b) -> [a] -> [a]
nubSortOn f = map snd . nubSortOn' fst . map (\x -> let y = f x in y `seq` (y, x))

-- |  This variant of 'nubSortOn' recomputes the sorting key for each comparison
nubSortOn' :: Ord b => (a -> b) -> [a] -> [a]
nubSortOn' f = nubSortBy (\x y -> compare (f x) (f y))

-- | On ordered lists,  'nub' is equivalent to 'Data.List.nub', except that
-- it runs in linear time instead of quadratic.   On unordered lists it also
-- removes elements that are smaller than any preceding element.
--
-- > nub [1,1,1,2,2] == [1,2]
-- > nub [2,0,1,3,3] == [2,3]
-- > nub = nubBy (<)
nub :: Ord a => [a] -> [a]
nub = nubBy (<)

-- | The 'nubBy' function is the greedy algorithm that returns a
-- sublist of its input such that:
--
-- > isSortedBy pred (nubBy pred xs) == True
--
-- This is true for all lists,  not just ordered lists,  and all binary
-- predicates,  not just total orders.   On infinite lists,  this statement
-- is true in a certain mathematical sense,  but not a computational one.
nubBy :: (a -> a -> Bool) -> [a] -> [a]
nubBy p []     = []
nubBy p (x:xs) = x : loop x xs
  where
    loop _ [] = []
    loop x (y:ys)
       | p x y     = y : loop y ys
       | otherwise = loop x ys

-- | The function @'foldt'' plus zero@ computes the sum of a list
-- using a balanced tree of operations.  'foldt'' necessarily diverges
-- on infinite lists, hence it is a stricter variant of 'foldt'.
-- 'foldt'' is used in the implementation of 'sort' and 'nubSort'.
foldt' :: (a -> a -> a) -> a -> [a] -> a
foldt' plus zero xs
  = case xs of
      []    -> zero
      (_:_) -> loop xs
  where
    loop [x] = x
    loop xs  = loop (pairs xs)

    pairs (x:y:zs) = plus x y : pairs zs
    pairs zs       = zs

-- | The function @'foldt' plus zero@ computes the sum of a list using
-- a sequence of balanced trees of operations.   Given an appropriate @plus@
-- operator,  this function can be productive on an infinite list, hence it
-- is lazier than 'foldt''.   'foldt' is used in the implementation of
-- 'mergeAll' and 'unionAll'.
foldt :: (a -> a -> a) -> a -> [a] -> a
foldt plus zero = loop
  where
    loop []     = zero
    loop (x:xs) = x `plus` loop (pairs xs)

    pairs (x:y:zs) = plus x y : pairs zs
    pairs zs       = zs

-- helper functions used in 'mergeAll' and 'unionAll'

data People a = VIP a (People a) | Crowd [a]

serve (VIP x xs) = x:serve xs
serve (Crowd xs) = xs

vips xss = [ VIP x (Crowd xs) | (x:xs) <- xss ]

-- | The 'mergeAll' function merges a (potentially) infinite number of
-- ordered lists, under the assumption that the heads of the inner lists
-- are sorted.  An element is duplicated in the result as many times as
-- the total number of occurrences in all inner lists.
--
-- The 'mergeAll' function is closely related to @'foldr' 'merge' []@.
-- The former does not assume that the outer list is finite, whereas
-- the latter does not assume that the heads of the inner lists are sorted.
-- When both sets of assumptions are met,  these two functions are
-- equivalent.
--
-- This implementation of 'mergeAll'  uses a tree of comparisons, and is
-- based on input from Dave Bayer, Heinrich Apfelmus, Omar Antolin Camarena,
-- and Will Ness.  See @CHANGES@ for details.
mergeAll :: Ord a => [[a]] -> [a]
mergeAll = mergeAllBy compare

-- | The 'mergeAllBy' function is the non-overloaded variant of the 'mergeAll'
-- function.
mergeAllBy :: (a -> a -> Ordering) -> [[a]] -> [a]
mergeAllBy cmp = serve . foldt merge' (Crowd []) . vips
  where
    merge' (VIP x xs) ys = VIP x (merge' xs ys)
    merge' (Crowd []) ys = ys
    merge' (Crowd xs) (Crowd ys) = Crowd (mergeBy cmp xs ys)
    merge' xs@(Crowd (x:xt)) ys@(VIP y yt)
      = case cmp x y of
         GT -> VIP y (merge' xs yt)
         _  -> VIP x (merge' (Crowd xt) ys)

-- | The 'unionAll' computes the union of a (potentially) infinite number
-- of lists,  under the assumption that the heads of the inner lists
-- are sorted.  The result will duplicate an element as many times as
-- the maximum number of occurrences in any single list.  Thus, the result
-- is a set if and only if every inner list is a set.
--
-- The 'unionAll' function is closely related to @'foldr' 'union' []@.
-- The former does not assume that the outer list is finite, whereas
-- the latter does not assume that the heads of the inner lists are sorted.
-- When both sets of assumptions are met,  these two functions are
-- equivalent.
--
-- Note that there is no simple way to express 'unionAll' in terms of
-- 'mergeAll' or vice versa on arbitrary valid inputs.  They are related
-- via 'nub' however,  as @'nub' . 'mergeAll' == 'unionAll' . 'map' 'nub'@.
-- If every list is a set,  then @map nub == id@,  and in this special case
-- (and only in this special case) does @nub . mergeAll == unionAll@.
--
-- This implementation of 'unionAll'  uses a tree of comparisons, and is
-- based on input from Dave Bayer, Heinrich Apfelmus, Omar Antolin Camarena,
-- and Will Ness.  See @CHANGES@ for details.
unionAll :: Ord a => [[a]] -> [a]
unionAll = unionAllBy compare

-- | The 'unionAllBy' function is the non-overloaded variant of the 'unionAll'
-- function.
unionAllBy :: (a -> a -> Ordering) -> [[a]] -> [a]
unionAllBy cmp = serve . foldt union' (Crowd []) . vips
  where
    msg = "Data.List.Ordered.unionAllBy:  the heads of the lists are not sorted"

    union' (VIP x xs) ys
       = VIP x $ case ys of
                  Crowd _ -> union' xs ys
                  VIP y yt -> case cmp x y of
                               LT -> union' xs ys
                               EQ -> union' xs yt
                               GT -> error msg
    union' (Crowd []) ys = ys
    union' (Crowd xs) (Crowd ys) = Crowd (unionBy cmp xs ys)
    union' xs@(Crowd (x:xt)) ys@(VIP y yt)
       = case cmp x y of
           LT -> VIP x (union' (Crowd xt) ys)
           EQ -> VIP x (union' (Crowd xt) yt)
           GT -> VIP y (union' xs yt)

main :: IO ()
main = do
  c <- getContents
  let l = (map (read :: String -> Int) . words) c
  let (n : m : k : ll) = l
  let a = [(0, 1, y, 0) | y <- [1..n]] ++ [(0, 2, y, 0) | y <- [1..m]] ++ mt ll 1
  let b = reverse a
  let b1 = filter (\(i, x, y, z) -> case x of {1 -> True; _ -> False}) b
  let b2 = filter (\(i, x, y, z) -> case x of {2 -> True; _ -> False}) b
  let c1 = nubSortBy fc b1
  let c2 = nubSortBy fc b2
  let c = [[q | (i2,x2,y2,z2) <- c2, let i = y1, let j = y2, let q = case compare i1 i2 of {GT -> z1; EQ -> z1; LT -> z2}] | (i1,x1,y1,z1) <- c1]
  putStrLn $ unlines . map (unwords . (map show)) $ c

fc :: (Int,Int,Int,Int) -> (Int,Int,Int,Int) -> Ordering
fc (i1,x1,y1,z1) (i2,x2,y2,z2) = compare y1 y2

mt :: [Int] -> Int -> [(Int, Int, Int, Int)]
mt [] _ = []
mt (a : b : c : ll) n = (n,a,b,c) : mt ll (n+1)

import Data.List(sort,sortBy,intersect)

-- |  The 'isSorted' predicate returns 'True' if the elements of a list occur
-- in non-descending order,  equivalent to @'isSortedBy' ('<=')@.
isSorted :: Ord a => [a] -> Bool
isSorted = isSortedBy (<=)

-- |  The 'isSortedBy' function returns 'True' iff the predicate returns true
-- for all adjacent pairs of elements in the list.
isSortedBy :: (a -> a -> Bool) -> [a] -> Bool
isSortedBy lte = loop
  where
    loop []       = True
    loop [_]      = True
    loop (x:y:zs) = (x `lte` y) && loop (y:zs)

-- |  The 'member' function returns 'True' if the element appears in the
-- ordered list.
member :: Ord a => a -> [a] -> Bool
member = memberBy compare

-- |  The 'memberBy' function is the non-overloaded version of 'member'.
memberBy :: (a -> a -> Ordering) -> a -> [a] -> Bool
memberBy cmp x = loop
  where
    loop []     = False
    loop (y:ys) = case cmp x y of
                    LT -> False
                    EQ -> True
                    GT -> loop ys

-- |  The 'has' function returns 'True' if the element appears in the list;
-- it is equivalent to 'member' except the order of the arguments is reversed,
-- making it a function from an ordered list to its characteristic function.
has :: Ord a => [a] -> a -> Bool
has xs y = memberBy compare y xs

-- |  The 'hasBy' function is the non-overloaded version of 'has'.
hasBy :: (a -> a -> Ordering) -> [a] -> a -> Bool
hasBy cmp xs y = memberBy cmp y xs

-- |  The 'insertBag' function inserts an element into a list.  If the element
-- is already there,  then another copy of the element is inserted.
insertBag :: Ord a => a -> [a] -> [a]
insertBag = insertBagBy compare

-- |  The 'insertBagBy' function is the non-overloaded version of 'insertBag'.
insertBagBy :: (a -> a -> Ordering) -> a -> [a] -> [a]
insertBagBy cmp = loop
  where
    loop x [] = [x]
    loop x (y:ys)
      = case cmp x y of
         GT -> y:loop x ys
         _  -> x:y:ys

-- |  The 'insertSet' function inserts an element into an ordered list.
-- If the element is already there,  then the element replaces the existing
-- element.
insertSet :: Ord a => a -> [a] -> [a]
insertSet = insertSetBy compare

-- |  The 'insertSetBy' function is the non-overloaded version of 'insertSet'.
insertSetBy :: (a -> a -> Ordering) -> a -> [a] -> [a]
insertSetBy cmp = loop
  where
    loop x [] = [x]
    loop x (y:ys) = case cmp x y of
            LT -> x:y:ys
            EQ -> x:ys
            GT -> y:loop x ys

{-
-- This function is moderately interesting,  as it encompasses all the
-- "Venn diagram" functions on two sets. (though not merge;  which isn't
-- a set function)

-- However, it doesn't seem that useful,  considering that of the 8 possible
-- functions,  there are only 4 interesting variations:  isect, union, minus,
-- and xunion.  Due to interactions with GHC's optimizer,  coded separately,
-- these have a smaller combined object code size than the object code size
-- for genSectBy.  (Or,  turn off certain optimizations and lose speed.)

-- Each individual object code can be recovered from genSectBy via GHC's
-- inliner and constant propagation;  but this doesn't save much in terms
-- of source code size and reduces portability.

-- Note that the Static Argument Transformation is necessary for this to work
-- correctly;  inlining genSectBy allows for cmp and p to be inlined as well,
-- or at least eliminate some indirect jumps.  All of the *By functions in
-- this module follow this idiom for this reason.

genSectBy :: (a -> a -> Ordering)
          -> (Bool -> Bool -> Bool)
          -> [a] -> [a] -> [a]
genSectBy cmp p = loop
  where
    loop [] ys | p False True = ys
               | otherwise    = []
    loop xs [] | p True False = xs
               | otherwise    = []
    loop (x:xs) (y:ys)
      = case cmp x y of
          LT | p True False -> x : loop xs (y:ys)
             | otherwise    ->     loop xs (y:ys)
          EQ | p True True  -> x : loop xs ys
             | otherwise    ->     loop xs ys
          GT | p False True -> y : loop (x:xs) ys
             | otherwise    ->     loop (x:xs) ys

-- Here's another variation that was suggested to me.  It is more general
-- than genSectBy, as it can implement a merge; but it cannot implement
-- a left-biased merge

foldrMergeBy :: (a -> b -> Ordering)
             -> (a -> c -> c) -> (b -> c -> c) -> (a -> b -> c -> c) -> c
             -> [a] -> [b] -> c
foldrMergeBy cmp addA addB unify z = loop
  where
    loop xs [] = foldr addA z xs
    loop [] ys = foldr addB z ys
    loop (x:xs) (y:ys)
      = case cmp x y of
          LT -> x `addA` loop  xs (y:ys)
          EQ -> unify x y (loop xs ys)
          GT -> y `addB` loop (x:xs) ys
-}

-- |  The 'isect' function computes the intersection of two ordered lists.
-- An element occurs in the output as many times as the minimum number of
-- occurrences in either input.  If either input is a set,  then the output
-- is a set.
--
-- > isect [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 3,4 ]
-- > isect [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1, 2,2 ]
isect :: Ord a => [a] -> [a] -> [a]
isect = isectBy compare

-- |  The 'isectBy' function is the non-overloaded version of 'isect'.
isectBy :: (a -> b -> Ordering) -> [a] -> [b] -> [a]
isectBy cmp = loop
  where
     loop [] _ys  = []
     loop _xs []  = []
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT ->     loop xs (y:ys)
          EQ -> x : loop xs ys
          GT ->     loop (x:xs) ys

-- |  The 'union' function computes the union of two ordered lists.
-- An element occurs in the output as many times as the maximum number
-- of occurrences in either input.  The output is a set if and only if
-- both inputs are sets.
--
-- > union [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2, 3,4, 5,6 ]
-- > union [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1,1, 2,2,2 ]
union :: Ord a => [a] -> [a] -> [a]
union = unionBy compare

-- |  The 'unionBy' function is the non-overloaded version of 'union'.
unionBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
unionBy cmp = loop
  where
     loop [] ys = ys
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ -> x : loop xs ys
          GT -> y : loop (x:xs) ys

-- |  The 'minus' function computes the difference of two ordered lists.
-- An element occurs in the output as many times as it occurs in
-- the first input, minus the number of occurrences in the second input.
-- If the first input is a set,  then the output is a set.
--
-- > minus [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2 ]
-- > minus [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 2 ]
minus :: Ord a => [a] -> [a] -> [a]
minus = minusBy compare

-- |  The 'minusBy' function is the non-overloaded version of 'minus'.
minusBy :: (a -> b -> Ordering) -> [a] -> [b] -> [a]
minusBy cmp = loop
  where
     loop [] _ys = []
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ ->     loop xs ys
          GT ->     loop (x:xs) ys

-- |  The 'minus'' function computes the difference of two ordered lists.
-- The result consists of elements from the first list that do not appear
-- in the second list.  If the first input is a set, then the output is
-- a set.
--
-- > minus' [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2 ]
-- > minus' [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == []
-- > minus' [ 1,1, 2,2 ] [ 2 ]          == [ 1,1 ]
minus' :: Ord a => [a] -> [a] -> [a]
minus' = minusBy' compare

-- |  The 'minusBy'' function is the non-overloaded version of 'minus''.
minusBy' :: (a -> b -> Ordering) -> [a] -> [b] -> [a]
minusBy' cmp = loop
  where
     loop [] _ys = []
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ ->     loop xs (y:ys)
          GT ->     loop (x:xs) ys

-- |  The 'xunion' function computes the exclusive union of two ordered lists.
-- An element occurs in the output as many times as the absolute difference
-- between the number of occurrences in the inputs.  If both inputs
-- are sets,  then the output is a set.
--
-- > xunion [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2, 5,6 ]
-- > xunion [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1, 2 ]
xunion :: Ord a => [a] -> [a] -> [a]
xunion = xunionBy compare

-- |  The 'xunionBy' function is the non-overloaded version of 'xunion'.
xunionBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
xunionBy cmp = loop
  where
     loop [] ys = ys
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ ->     loop xs ys
          GT -> y : loop (x:xs) ys

-- |  The 'merge' function combines all elements of two ordered lists.
-- An element occurs in the output as many times as the sum of the
-- occurrences in both lists.   The output is a set if and only if
-- the inputs are disjoint sets.
--
-- > merge [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2,  3,3,4,4,  5,6 ]
-- > merge [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1,1,1,  2,2,2,2,2 ]
merge :: Ord a => [a] -> [a] -> [a]
merge = mergeBy compare

-- |  The 'mergeBy' function is the non-overloaded version of 'merge'.
mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
mergeBy cmp = loop
  where
    loop [] ys  = ys
    loop xs []  = xs
    loop (x:xs) (y:ys)
      = case cmp x y of
         GT -> y : loop (x:xs) ys
         _  -> x : loop xs (y:ys)

-- |  The 'subset' function returns true if the first list is a sub-list
-- of the second.
subset :: Ord a => [a] -> [a] -> Bool
subset = subsetBy compare

-- |  The 'subsetBy' function is the non-overloaded version of 'subset'.
subsetBy :: (a -> a -> Ordering) -> [a] -> [a] -> Bool
subsetBy cmp = loop
  where
    loop [] _ys = True
    loop _xs [] = False
    loop (x:xs) (y:ys)
      = case cmp x y of
         LT -> False
         EQ -> loop xs ys
         GT -> loop (x:xs) ys

{-
-- This is Ian Lynagh's mergesort implementation,  which appeared as
-- Data.List.sort, with the static argument transformation applied.
-- It's not clear whether this modification is truly worthwhile or not.

sort :: Ord a => [a] -> [a]
sort = sortBy compare

sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortBy cmp = foldt (mergeBy cmp) [] . map (\x -> [x])
-}

-- |  The 'sortOn' function provides the decorate-sort-undecorate idiom,
-- also known as the \"Schwartzian transform\".
sortOn :: Ord b => (a -> b) -> [a] -> [a]
sortOn f  = map snd . sortOn' fst .  map (\x -> let y = f x in y `seq` (y, x))

-- |  This variant of 'sortOn' recomputes the sorting key every comparison.
-- This can be better for functions that are cheap to compute.
-- This is definitely better for projections,  as the decorate-sort-undecorate
-- saves nothing and adds two traversals of the list and extra memory
-- allocation.
sortOn' :: Ord b => (a -> b) -> [a] -> [a]
sortOn' f = sortBy (\x y -> compare (f x) (f y))

-- |  The 'nubSort' function is equivalent to @'nub' '.' 'sort'@,  except
-- that duplicates are removed as it sorts. It is essentially the same
-- implementation as @Data.List.sort@, with 'merge' replaced by 'union'.
-- Thus the performance of 'nubSort' should better than or nearly equal
-- to 'sort' alone.  It is faster than both 'sort' and @'nub' '.' 'sort'@
-- when the input contains significant quantities of duplicated elements.
nubSort :: Ord a => [a] -> [a]
nubSort = nubSortBy compare

-- |  The 'nubSortBy' function is the non-overloaded version of 'nubSort'.
nubSortBy :: (a -> a -> Ordering) -> [a] -> [a]
nubSortBy cmp = foldt' (unionBy cmp) [] . runs
  where
    -- 'runs' partitions the input into sublists that are monotonic,
    -- contiguous,  and non-overlapping.   Descending runs are reversed
    -- and adjacent duplicates are eliminated,  so every run returned is
    -- strictly ascending.

    runs (a:b:xs)
      = case cmp a b of
          LT -> asc b (a:) xs
          EQ -> runs (a:xs)
          GT -> desc b [a] xs
    runs xs = [xs]

    desc a as []  = [a:as]
    desc a as (b:bs)
      = case cmp a b of
          LT -> (a:as) : runs (b:bs)
          EQ -> desc a as bs
          GT -> desc b (a:as) bs

    asc a as [] = [as [a]]
    asc a as (b:bs)
      = case cmp a b of
         LT -> asc b (\ys -> as (a:ys)) bs
         EQ -> asc a as bs
         GT -> as [a] : runs (b:bs)

-- |  The 'nubSortOn' function provides decorate-sort-undecorate for 'nubSort'.
nubSortOn :: Ord b => (a -> b) -> [a] -> [a]
nubSortOn f = map snd . nubSortOn' fst . map (\x -> let y = f x in y `seq` (y, x))

-- |  This variant of 'nubSortOn' recomputes the sorting key for each comparison
nubSortOn' :: Ord b => (a -> b) -> [a] -> [a]
nubSortOn' f = nubSortBy (\x y -> compare (f x) (f y))

-- | On ordered lists,  'nub' is equivalent to 'Data.List.nub', except that
-- it runs in linear time instead of quadratic.   On unordered lists it also
-- removes elements that are smaller than any preceding element.
--
-- > nub [1,1,1,2,2] == [1,2]
-- > nub [2,0,1,3,3] == [2,3]
-- > nub = nubBy (<)
nub :: Ord a => [a] -> [a]
nub = nubBy (<)

-- | The 'nubBy' function is the greedy algorithm that returns a
-- sublist of its input such that:
--
-- > isSortedBy pred (nubBy pred xs) == True
--
-- This is true for all lists,  not just ordered lists,  and all binary
-- predicates,  not just total orders.   On infinite lists,  this statement
-- is true in a certain mathematical sense,  but not a computational one.
nubBy :: (a -> a -> Bool) -> [a] -> [a]
nubBy p []     = []
nubBy p (x:xs) = x : loop x xs
  where
    loop _ [] = []
    loop x (y:ys)
       | p x y     = y : loop y ys
       | otherwise = loop x ys

-- | The function @'foldt'' plus zero@ computes the sum of a list
-- using a balanced tree of operations.  'foldt'' necessarily diverges
-- on infinite lists, hence it is a stricter variant of 'foldt'.
-- 'foldt'' is used in the implementation of 'sort' and 'nubSort'.
foldt' :: (a -> a -> a) -> a -> [a] -> a
foldt' plus zero xs
  = case xs of
      []    -> zero
      (_:_) -> loop xs
  where
    loop [x] = x
    loop xs  = loop (pairs xs)

    pairs (x:y:zs) = plus x y : pairs zs
    pairs zs       = zs

-- | The function @'foldt' plus zero@ computes the sum of a list using
-- a sequence of balanced trees of operations.   Given an appropriate @plus@
-- operator,  this function can be productive on an infinite list, hence it
-- is lazier than 'foldt''.   'foldt' is used in the implementation of
-- 'mergeAll' and 'unionAll'.
foldt :: (a -> a -> a) -> a -> [a] -> a
foldt plus zero = loop
  where
    loop []     = zero
    loop (x:xs) = x `plus` loop (pairs xs)

    pairs (x:y:zs) = plus x y : pairs zs
    pairs zs       = zs

-- helper functions used in 'mergeAll' and 'unionAll'

data People a = VIP a (People a) | Crowd [a]

serve (VIP x xs) = x:serve xs
serve (Crowd xs) = xs

vips xss = [ VIP x (Crowd xs) | (x:xs) <- xss ]

-- | The 'mergeAll' function merges a (potentially) infinite number of
-- ordered lists, under the assumption that the heads of the inner lists
-- are sorted.  An element is duplicated in the result as many times as
-- the total number of occurrences in all inner lists.
--
-- The 'mergeAll' function is closely related to @'foldr' 'merge' []@.
-- The former does not assume that the outer list is finite, whereas
-- the latter does not assume that the heads of the inner lists are sorted.
-- When both sets of assumptions are met,  these two functions are
-- equivalent.
--
-- This implementation of 'mergeAll'  uses a tree of comparisons, and is
-- based on input from Dave Bayer, Heinrich Apfelmus, Omar Antolin Camarena,
-- and Will Ness.  See @CHANGES@ for details.
mergeAll :: Ord a => [[a]] -> [a]
mergeAll = mergeAllBy compare

-- | The 'mergeAllBy' function is the non-overloaded variant of the 'mergeAll'
-- function.
mergeAllBy :: (a -> a -> Ordering) -> [[a]] -> [a]
mergeAllBy cmp = serve . foldt merge' (Crowd []) . vips
  where
    merge' (VIP x xs) ys = VIP x (merge' xs ys)
    merge' (Crowd []) ys = ys
    merge' (Crowd xs) (Crowd ys) = Crowd (mergeBy cmp xs ys)
    merge' xs@(Crowd (x:xt)) ys@(VIP y yt)
      = case cmp x y of
         GT -> VIP y (merge' xs yt)
         _  -> VIP x (merge' (Crowd xt) ys)

-- | The 'unionAll' computes the union of a (potentially) infinite number
-- of lists,  under the assumption that the heads of the inner lists
-- are sorted.  The result will duplicate an element as many times as
-- the maximum number of occurrences in any single list.  Thus, the result
-- is a set if and only if every inner list is a set.
--
-- The 'unionAll' function is closely related to @'foldr' 'union' []@.
-- The former does not assume that the outer list is finite, whereas
-- the latter does not assume that the heads of the inner lists are sorted.
-- When both sets of assumptions are met,  these two functions are
-- equivalent.
--
-- Note that there is no simple way to express 'unionAll' in terms of
-- 'mergeAll' or vice versa on arbitrary valid inputs.  They are related
-- via 'nub' however,  as @'nub' . 'mergeAll' == 'unionAll' . 'map' 'nub'@.
-- If every list is a set,  then @map nub == id@,  and in this special case
-- (and only in this special case) does @nub . mergeAll == unionAll@.
--
-- This implementation of 'unionAll'  uses a tree of comparisons, and is
-- based on input from Dave Bayer, Heinrich Apfelmus, Omar Antolin Camarena,
-- and Will Ness.  See @CHANGES@ for details.
unionAll :: Ord a => [[a]] -> [a]
unionAll = unionAllBy compare

-- | The 'unionAllBy' function is the non-overloaded variant of the 'unionAll'
-- function.
unionAllBy :: (a -> a -> Ordering) -> [[a]] -> [a]
unionAllBy cmp = serve . foldt union' (Crowd []) . vips
  where
    msg = "Data.List.Ordered.unionAllBy:  the heads of the lists are not sorted"

    union' (VIP x xs) ys
       = VIP x $ case ys of
                  Crowd _ -> union' xs ys
                  VIP y yt -> case cmp x y of
                               LT -> union' xs ys
                               EQ -> union' xs yt
                               GT -> error msg
    union' (Crowd []) ys = ys
    union' (Crowd xs) (Crowd ys) = Crowd (unionBy cmp xs ys)
    union' xs@(Crowd (x:xt)) ys@(VIP y yt)
       = case cmp x y of
           LT -> VIP x (union' (Crowd xt) ys)
           EQ -> VIP x (union' (Crowd xt) yt)
           GT -> VIP y (union' xs yt)

main :: IO ()
main = do
  c <- getContents
  let l = (map (read :: String -> Int) . words) c
  let (n : m : k : ll) = l
  let a = [(0, 1, y, 0) | y <- [1..n]] ++ [(0, 2, y, 0) | y <- [1..m]] ++ mt ll 1
  let b = reverse a
  let b1 = filter (\(i, x, y, z) -> case x of {1 -> True; _ -> False}) b
  let b2 = filter (\(i, x, y, z) -> case x of {2 -> True; _ -> False}) b
  let c1 = nubSortBy fc b1
  let c2 = nubSortBy fc b2
--  putStrLn $ show $ sum (map (\(i, x, y, z) -> z) c1 :: [Int])
--  putStrLn $ show $ sum (map (\(i, x, y, z) -> z) c2 :: [Int])
  let c = [[q | (i2,x2,y2,z2) <- c2, let i = y1, let j = y2, let q = case compare i1 i2 of {GT -> z1; EQ -> z1; LT -> z2}] | (i1,x1,y1,z1) <- c1]
  putStrLn $ unlines . map (unwords . (map show)) $ c

fc :: (Int,Int,Int,Int) -> (Int,Int,Int,Int) -> Ordering
fc (i1,x1,y1,z1) (i2,x2,y2,z2) = compare y1 y2

mt :: [Int] -> Int -> [(Int, Int, Int, Int)]
mt [] _ = []
mt (a : b : c : ll) n = (n,a,b,c) : mt ll (n+1)

import Data.List(sort,sortBy,intersect)

--import Data.List.Ordered

-- |  The 'union' function computes the union of two ordered lists.
-- An element occurs in the output as many times as the maximum number
-- of occurrences in either input.  The output is a set if and only if
-- both inputs are sets.
--
-- > union [ 1,2, 3,4 ] [ 3,4, 5,6 ]   == [ 1,2, 3,4, 5,6 ]
-- > union [ 1, 2,2,2 ] [ 1,1,1, 2,2 ] == [ 1,1,1, 2,2,2 ]
union :: Ord a => [a] -> [a] -> [a]
union = unionBy compare

-- |  The 'unionBy' function is the non-overloaded version of 'union'.
unionBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]
unionBy cmp = loop
  where
     loop [] ys = ys
     loop xs [] = xs
     loop (x:xs) (y:ys)
       = case cmp x y of
          LT -> x : loop xs (y:ys)
          EQ -> x : loop xs ys
          GT -> y : loop (x:xs) ys

-- |  The 'nubSort' function is equivalent to @'nub' '.' 'sort'@,  except
-- that duplicates are removed as it sorts. It is essentially the same
-- implementation as @Data.List.sort@, with 'merge' replaced by 'union'.
-- Thus the performance of 'nubSort' should better than or nearly equal
-- to 'sort' alone.  It is faster than both 'sort' and @'nub' '.' 'sort'@
-- when the input contains significant quantities of duplicated elements.
nubSort :: Ord a => [a] -> [a]
nubSort = nubSortBy compare

-- |  The 'nubSortBy' function is the non-overloaded version of 'nubSort'.
nubSortBy :: (a -> a -> Ordering) -> [a] -> [a]
nubSortBy cmp = foldt' (unionBy cmp) [] . runs
  where
    -- 'runs' partitions the input into sublists that are monotonic,
    -- contiguous,  and non-overlapping.   Descending runs are reversed
    -- and adjacent duplicates are eliminated,  so every run returned is
    -- strictly ascending.

    runs (a:b:xs)
      = case cmp a b of
          LT -> asc b (a:) xs
          EQ -> runs (a:xs)
          GT -> desc b [a] xs
    runs xs = [xs]

    desc a as []  = [a:as]
    desc a as (b:bs)
      = case cmp a b of
          LT -> (a:as) : runs (b:bs)
          EQ -> desc a as bs
          GT -> desc b (a:as) bs

    asc a as [] = [as [a]]
    asc a as (b:bs)
      = case cmp a b of
         LT -> asc b (\ys -> as (a:ys)) bs
         EQ -> asc a as bs
         GT -> as [a] : runs (b:bs)

-- | The function @'foldt'' plus zero@ computes the sum of a list
-- using a balanced tree of operations.  'foldt'' necessarily diverges
-- on infinite lists, hence it is a stricter variant of 'foldt'.
-- 'foldt'' is used in the implementation of 'sort' and 'nubSort'.
foldt' :: (a -> a -> a) -> a -> [a] -> a
foldt' plus zero xs
  = case xs of
      []    -> zero
      (_:_) -> loop xs
  where
    loop [x] = x
    loop xs  = loop (pairs xs)

    pairs (x:y:zs) = plus x y : pairs zs
    pairs zs       = zs

main :: IO ()
main = do
  c <- getContents
  let l = (map (read :: String -> Int) . words) c
  let (n : m : k : ll) = l
  let a = [(0, 1, y, 0) | y <- [1..n]] ++ [(0, 2, y, 0) | y <- [1..m]] ++ mt ll 1
  let b = reverse a
  let b1 = filter (\(i, x, y, z) -> case x of {1 -> True; _ -> False}) b
  let b2 = filter (\(i, x, y, z) -> case x of {2 -> True; _ -> False}) b
  let c1 = nubSortBy fc b1
  let c2 = nubSortBy fc b2
  let c = [[q | (i2,x2,y2,z2) <- c2, let i = y1, let j = y2, let q = case compare i1 i2 of {GT -> z1; EQ -> z1; LT -> z2}] | (i1,x1,y1,z1) <- c1]
  putStrLn $ unlines . map (unwords . (map show)) $ c

mt :: [Int] -> Int -> [(Int, Int, Int, Int)]
mt [] _ = []
mt (a : b : c : ll) n = (n,a,b,c) : mt ll (n+1)

fc :: (Int,Int,Int,Int) -> (Int,Int,Int,Int) -> Ordering
fc (i1,x1,y1,z1) (i2,x2,y2,z2) = compare y1 y2

{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
{-# OPTIONS_GHC -O2 #-}

import Control.Applicative
import Control.Monad
import Control.Monad.ST.Safe
import Control.Monad.State
import Data.Array.IArray
import Data.Array.IO.Safe
import Data.Array.MArray.Safe
import Data.Array.ST.Safe
import Data.Array.Unboxed
import Data.Char
import Data.Function
-- import Data.Graph
import Data.Int
import Data.List
import Data.List.Split
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
-- import Data.Tree
import Data.Tuple
import Data.Map (Map)
import qualified Data.Map as Map
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import qualified Data.ByteString.Char8 as B
-- import Debug.Trace

import qualified Data.ByteString.Lazy.Builder as BB

import Data.Monoid
import System.IO

-- getInts = fmap (map read . words) getLine
getInts = unfoldr (B.readInt . B.dropWhile isSpace) <$> B.getLine

main = do
  [n, m, k] <- getInts

  as <- newArray (1, n) 0 :: IO (IOUArray Int Int)
  bs <- newArray (1, m) 0 :: IO (IOUArray Int Int)
  cs <- newArray (1, k) 0 :: IO (IOUArray Int Int)

  forM_ [1..k] $ \i -> do
    [t, j, c] <- getInts
    if t == 1
      then writeArray as j i
      else writeArray bs j i
    writeArray cs i c

  as' <- freeze as :: IO (UArray Int Int)
  bs' <- freeze bs :: IO (UArray Int Int)
  cs' <- freeze cs :: IO (UArray Int Int)

  forM_ [1..n] $ \i -> do
    let
      f j = if k == 0 then 0 else cs'!k where k = max (as'!i) (bs'!j)

      l = mconcat $ map (\j -> (BB.intDec $ f j) <> BB.char8 ' ') [1..m]

    BB.hPutBuilder stdout $ l <> BB.char8 '\n'

{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
{-# OPTIONS_GHC -O2 #-}

import Control.Applicative
import Control.Monad
import Control.Monad.ST.Safe
import Control.Monad.State
import Data.Array.IArray
import Data.Array.IO.Safe
import Data.Array.MArray.Safe
import Data.Array.ST.Safe
import Data.Array.Unboxed
import Data.Char
import Data.Function
-- import Data.Graph
import Data.Int
import Data.List
import Data.List.Split
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
-- import Data.Tree
import Data.Tuple
import Data.Map (Map)
import qualified Data.Map as Map
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import qualified Data.ByteString.Char8 as B
-- import Debug.Trace

import qualified Data.ByteString.Lazy.Builder as BB

import Data.Monoid
import System.IO

-- getInts = fmap (map read . words) getLine
getInts = unfoldr (B.readInt . B.dropWhile isSpace) <$> B.getLine

main = do
  [n, m, k] <- getInts

  as <- newArray (1, n) 0 :: IO (IOUArray Int Int)
  bs <- newArray (1, m) 0 :: IO (IOUArray Int Int)
  cs <- newArray (1, k) 0 :: IO (IOUArray Int Int)

  forM_ [1..k] $ \i -> do
    [t, j, c] <- getInts
    if t == 1
      then writeArray as j i
      else writeArray bs j i
    writeArray cs i c

  as' <- freeze as :: IO (UArray Int Int)
  bs' <- freeze bs :: IO (UArray Int Int)
  cs' <- freeze cs :: IO (UArray Int Int)

  let
    r = [map (f i) [1..m] | i <- [1..n]]
      where
        f i j = if k == 0 then 0 else cs'!k where k = max (as'!i) (bs'!j)

  putStr $ unlines $ map (unwords . map show) r

{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
{-# OPTIONS_GHC -O2 #-}

import Control.Applicative
import Control.Monad
import Control.Monad.ST.Safe
import Control.Monad.State
import Data.Array.IArray
import Data.Array.IO.Safe
import Data.Array.MArray.Safe
import Data.Array.ST.Safe
import Data.Array.Unboxed
import Data.Char
import Data.Function
-- import Data.Graph
import Data.Int
import Data.List
import Data.List.Split
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
-- import Data.Tree
import Data.Tuple
import Data.Map (Map)
import qualified Data.Map as Map
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import qualified Data.ByteString.Char8 as B
-- import Debug.Trace

import qualified Data.ByteString.Lazy.Builder as BB

import Data.Monoid
import System.IO

-- getInts = fmap (map read . words) getLine
getInts = unfoldr (B.readInt . B.dropWhile isSpace) <$> B.getLine

main = do
  [n, m, k] <- getInts

  as <- newArray (1, n) 0 :: IO (IOUArray Int Int)
  bs <- newArray (1, m) 0 :: IO (IOUArray Int Int)
  cs <- newArray (1, k) 0 :: IO (IOUArray Int Int)

  forM_ [1..k] $ \i -> do
    [t, j, c] <- getInts
    if t == 1
      then writeArray as j i
      else writeArray bs j i
    writeArray cs i c

  as' <- freeze as :: IO (UArray Int Int)
  bs' <- freeze bs :: IO (UArray Int Int)
  cs' <- freeze cs :: IO (UArray Int Int)

  forM_ [1..n] $ \i -> do
    let
      f j = if k == 0 then 0 else cs'!k where k = max (as'!i) (bs'!j)

    putStrLn $ unlines $ map show $ map f [1..m]

{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-}
{-# OPTIONS_GHC -O2 #-}

import Control.Applicative
import Control.Monad
import Control.Monad.ST.Safe
import Control.Monad.State
import Data.Array.IArray
import Data.Array.IO.Safe
import Data.Array.MArray.Safe
import Data.Array.ST.Safe
import Data.Array.Unboxed
import Data.Char
import Data.Function
-- import Data.Graph
import Data.Int
import Data.List
import Data.List.Split
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
-- import Data.Tree
import Data.Tuple
import Data.Map (Map)
import qualified Data.Map as Map
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import qualified Data.ByteString.Char8 as B
-- import Debug.Trace

import qualified Data.ByteString.Lazy.Builder as BB

import Data.Monoid
import System.IO

-- getInts = fmap (map read . words) getLine
getInts = unfoldr (B.readInt . B.dropWhile isSpace) <$> B.getLine

main = do
  [n, m, k] <- getInts

  as <- newArray (1, n) 0 :: IO (IOUArray Int Int)
  bs <- newArray (1, m) 0 :: IO (IOUArray Int Int)
  cs <- newArray (1, k) 0 :: IO (IOUArray Int Int)

  forM_ [1..k] $ \i -> do
    [t, j, c] <- getInts
    if t == 1
      then writeArray as j i
      else writeArray bs j i
    writeArray cs i c

  as' <- freeze as :: IO (UArray Int Int)
  bs' <- freeze bs :: IO (UArray Int Int)
  cs' <- freeze cs :: IO (UArray Int Int)

  forM_ [1..n] $ \i -> do
  let
    r = [map (f i) [1..m] | i <- [1..n]]
      where
        f i j = if k == 0 then 0 else cs'!k where k = max (as'!i) (bs'!j)

  putStr $ unlines $ map (unwords . map show) r


You are given a tree consisting of $$$n$$$ vertices. Initially, each vertex has a value $$$0$$$.You need to perform $$$m$$$ queries of two types:   You are given a vertex index $$$v$$$. Print the value of the vertex $$$v$$$.  You are given two vertex indices $$$u$$$ and $$$v$$$ and values $$$k$$$ and $$$d$$$ ($$$d \le 20$$$). You need to add $$$k$$$ to the value of each vertex such that the distance from that vertex to the path from $$$u$$$ to $$$v$$$ is less than or equal to $$$d$$$. The distance between two vertices $$$x$$$ and $$$y$$$ is equal to the number of edges on the path from $$$x$$$ to $$$y$$$. For example, the distance from $$$x$$$ to $$$x$$$ itself is equal to $$$0$$$.The distance from the vertex $$$v$$$ to some path from $$$x$$$ to $$$y$$$ is equal to the minimum among distances from $$$v$$$ to any vertex on the path from $$$x$$$ to $$$y$$$.

The first line contains a single integer $$$n$$$ ($$$2 \le n \le 2 \cdot 10^5$$$) — the number of vertices in the tree. Next $$$n - 1$$$ lines contain the edges of the tree — one per line. Each line contains two integers $$$u$$$ and $$$v$$$ ($$$1 \le u, v \le n$$$; $$$u \neq v$$$) representing one edge of the tree. It's guaranteed that the given edges form a tree. The next line contains a single integer $$$m$$$ ($$$1 \le m \le 2 \cdot 10^5$$$) — the number of queries. Next $$$m$$$ lines contain the queries — one per line. Each query has one of the following two types:    $$$1$$$ $$$v$$$ ($$$1 \le v \le n$$$) — the query of the first type;  $$$2$$$ $$$u$$$ $$$v$$$ $$$k$$$ $$$d$$$ ($$$1 \le u, v \le n$$$; $$$1 \le k \le 1000$$$; $$$0 \le d \le 20$$$) — the query of the second type.  Additional constraint on the input: there is at least one query of the first type.

For each query of the first type, print the value of the corresponding vertex.

{-# LANGUAGE CPP, BlockArguments, DatatypeContexts, DeriveFunctor, GADTs, LambdaCase, RecursiveDo, NumericUnderscores, OverloadedStrings, ScopedTypeVariables, TupleSections #-}
#ifndef DEBUG
{-# LANGUAGE Safe #-}
#endif
{-# LANGUAGE Strict #-}
{-# OPTIONS_GHC -O3 -funbox-strict-fields -fvia-C -optc-O3 #-}

import Control.Arrow ((>>>))
import Control.Monad (
    MonadPlus (mplus),
    foldM_,
    forM_,
    guard,
    join,
    replicateM,
    replicateM_,
 )
import qualified Control.Monad as M
import qualified Control.Monad.ST.Strict as ST
import qualified Control.Monad.State.Strict as S
import qualified Control.Monad.Trans.Class as T
import qualified Control.Monad.Trans.Maybe as MT

import qualified Data.Array as A
import qualified Data.Array.MArray.Safe as MA
import qualified Data.Array.IO.Safe as IOA
import qualified Data.Array.ST.Safe as STA
import qualified Data.Array.Unboxed as UA

import Data.Bits
import qualified Data.ByteString.Char8 as B8
import Data.Char
import Data.Int
import Data.Tuple

import Data.Function (on)
import Data.Functor ((<&>))
import Data.Bifunctor (bimap)
import Data.Maybe (fromJust, fromMaybe, isJust)
import qualified Data.Maybe as MB
import Data.Foldable

import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.List   as L
import Data.List (
    elemIndices,
    find,
    findIndices,
    intersect,
    isPrefixOf,
    nub,
    sort,
    sortOn,
 )
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Ix as Ix
import qualified Data.Ratio as R

import Control.Monad.Cont (MonadIO (liftIO))
import Data.IORef (modifyIORef, newIORef, readIORef)
import GHC.IO.Handle (hDuplicateTo)
import System.IO (
    IOMode (ReadMode, WriteMode),
    openFile,
    stdin,
    stdout,
    hFlush
 )
import System.Posix.Internals (puts)
import Text.Printf (printf)
import qualified Data.Array.IO.Safe as UOA

#ifdef DEBUG
import Debug.Trace (trace, traceM, traceShowM)
import Data.Graph (vertices)
debug = flip trace

tracing t x = trace (t ++ " = " ++ show x) x
debugging x t = tracing t x

tracingM t x = traceM $ t ++ " = " ++ show x

#else

debug x _ = x
trace _ x = x
tracing _ x = x
debugging x _ = x

traceM _ = pure ()
tracingM _ _ = pure ()
#endif

readIntB8 :: B8.ByteString -> Int
readIntB8 = B8.readInt >>> (fst . fromJust)

readIntB8s :: B8.ByteString -> [Int]
readIntB8s = B8.words >>> map (B8.readInt >>> (fst . fromJust))

readIntegerB8 :: B8.ByteString -> Integer
readIntegerB8 = B8.readInteger >>> (fst . fromJust)

readIntegerB8s :: B8.ByteString -> [Integer]
readIntegerB8s = B8.words >>> map (B8.readInteger >>> (fst . fromJust))

{-# INLINE modifyArray #-}
{-# SCC modifyArray #-}
modifyArray :: (MA.MArray a e m, MA.Ix i) => a i e -> i -> (e -> e) -> m ()
modifyArray arr ix f = do
    value <- MA.readArray arr ix
    MA.writeArray arr ix $ f value

putsYesNo :: Bool -> IO ()
putsYesNo value = do
    let result :: String =
            if value
                then "YES"
                else "NO"
    printf "%s\n" result

whileM :: (Monad m) => m Bool -> m () -> m ()
whileM f m = do
    t <- f
    M.when t $ do
        m
        whileM f m

iterateWhileM :: (Monad m) => (a -> Bool) -> a -> (a -> m a) -> m [a]
iterateWhileM check x f = do
    y <- f x
    (x:) <$> if check x
        then iterateWhileM check y f
        else M.return []

{- END OF GENERAL -}

type TreeOf a = A.Array Int a
type Tree = TreeOf [Int]
type Edge = (Int, Int)

buildTree :: Int -> [Edge] -> Tree
buildTree n edges = tree
    where
        tree = A.accumArray (flip (:)) [] (1, n) (edges ++ map swap edges)

type JumpTable = A.Array (Int, Int) Int
type State = (JumpTable, TreeOf (Int, Int))

maxK = 17
maxD = 20

preSolve :: Int -> Int -> Tree -> State
preSolve n root tree = ST.runST $ do
    jumpTable <- MA.newArray ((1, 0), (n, maxK)) root :: ST.ST s (STA.STArray s (Int, Int) Int)
    timeRanges <- MA.newArray (1, n) (0, n) :: ST.ST s (STA.STArray s Int (Int, Int))

    -- augh.. learn mfix please
    let dfs arrs v p = flip S.evalStateT 0 $ do
            dfs' arrs v p
        dfs' arrs@(jumpTable, timeRanges) v p = do
            T.lift $ MA.writeArray jumpTable (v, 0) p
            M.forM_ [1 .. maxK] $ \jump -> do
                halfJumpV <- T.lift $ MA.readArray jumpTable (v, jump - 1)
                jumpV <- T.lift $ MA.readArray jumpTable (halfJumpV, jump - 1)
                T.lift $ MA.writeArray jumpTable (v, jump) jumpV

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(_, to) -> (time, to)

            M.forM_ (tree A.! v) $ \u -> do
                M.when (u /= p) $ do
                    dfs' arrs u v

            time <- S.get
            T.lift $ modifyArray timeRanges v $ \(from, _) -> (from, time)

    dfs (jumpTable, timeRanges) root root

    jumpTableA <- STA.freeze jumpTable
    timeRangesA <- STA.freeze timeRanges
    return (jumpTableA, timeRangesA)

{-# INLINE isParent #-}
isParent :: Int -> Int -> TreeOf (Int, Int) -> Bool
isParent u v timeRanges = uFrom <= vFrom && vTo <= uTo
    where
        (uFrom, uTo) = timeRanges A.! u
        (vFrom, vTo) = timeRanges A.! v

lca :: Int -> Int -> State -> Int
lca u v (jumpTable, timeRanges)
    | isParent u v timeRanges = u
    | isParent v u timeRanges = v
    | otherwise = jumpTable A.! (lca', 0)
        where
            liftVertex jump v' = let
                    jumpV' =  jumpTable A.! (v', jump)
                in
                    if isParent jumpV' u timeRanges
                        then v'
                        else jumpV'

            lca' = L.foldr liftVertex v [0 .. maxK]

type STFenwickTree s = STA.STUArray s Int Int

{-# INLINE fenwickAdd #-}
{-# SCC fenwickAdd #-}
fenwickAdd :: STFenwickTree s -> Int -> Int -> Int -> ST.ST s ()
fenwickAdd f i x n = fenwickAdd' i
    where
        fenwickAdd' j = M.when (j <= n) do
            modifyArray f j (+ x)
            fenwickAdd' $ j - (j .|. (- j))

{-# INLINE fenwickGet #-}
{-# SCC fenwickGet #-}
fenwickGet :: STFenwickTree s -> Int -> ST.ST s Int
fenwickGet f i = fenwickGet' i
    where
        fenwickGet' j = if j <= 0
            then pure 0
            else do
                s <- fenwickGet' $ j + (j .|. (- j))
                ds <- MA.readArray f j
                return $ s + ds

data Query = Get Int | Modify Int Int Int Int
    deriving (Show)

solve :: Int -> Tree -> State -> [Query] -> [Int]
solve n tree state@(jumpTable, timeRanges) queries = ST.runST $ do
    let fenwickN = n
    fenwicks <- A.listArray (0, maxD) <$> M.replicateM (maxD + 1) (MA.newArray (1, fenwickN + 10) 0) :: ST.ST s (A.Array Int (STA.STUArray s Int Int))

    answers <- M.forM queries $ \case
        q@(Get v) -> do
            let get v level = do
                    let parent = jumpTable A.! (v, 0)
                    s <- if level >= maxD
                        then pure 0
                        else get parent (level + 1)

                    let (fromTime, toTime) = timeRanges A.! v
                    toSum <- fenwickGet (fenwicks A.! level) toTime
                    fromSum <- fenwickGet (fenwicks A.! level) (fromTime - 1)
                    return $ s + toSum - fromSum
            answer <- get v 0
            return $ Just answer

        q@(Modify u v k d) -> do
            let lca' = lca u v state
            let addPath fenwick k v pv = do
                    let (fromV, _) = timeRanges A.! v
                    let (fromPv, _) = timeRanges A.! pv
                    fenwickAdd fenwick fromV k fenwickN
                    fenwickAdd fenwick fromPv (-k) fenwickN
            M.when (lca' /= v) $ addPath (fenwicks A.! d) k v lca'
            M.when (lca' /= u) $ addPath (fenwicks A.! d) k u lca'

            let add v level = do
                    let parent = jumpTable A.! (v, 0)
                    addPath (fenwicks A.! (d - level)) k v parent
                    M.when (level < d) $ do
                        addPath (fenwicks A.! (d - level - 1)) k v parent
                        add parent (level + 1)
            add lca' 0
            return $ Nothing
    return $ MB.catMaybes answers

main :: IO ()
main = do
    n <- B8.getLine <&> readIntB8
    edges <- M.replicateM (n - 1) $ do
        [u, v] <- B8.getLine <&> readIntB8s
        return $ (u, v)

    let verticesCount = n + maxD + 2
        fakeRoot = n + maxD + 2
        fakeVertices = [n + 1 .. n + maxD + 2]
        fakeEdges = L.zip (1:fakeVertices) fakeVertices

    let tree = buildTree verticesCount $ edges ++ fakeEdges
    let state = preSolve verticesCount fakeRoot tree

    m <- B8.getLine <&> readIntB8
    queries <- M.replicateM m $ do
        qValues <- B8.getLine <&> readIntB8s
        return $ case qValues of
            [1, v] -> Get v
            [2, u, v, k, d] -> Modify u v k d

    let answers = solve verticesCount tree state queries
    forM_ answers $ printf "%d\n"

{-# LANGUAGE CPP, BlockArguments, DatatypeContexts, DeriveFunctor, GADTs, LambdaCase, RecursiveDo, NumericUnderscores, OverloadedStrings, ScopedTypeVariables, TupleSections #-}
#ifndef DEBUG
{-# LANGUAGE Safe #-}
#endif
{-# LANGUAGE Strict #-}
{-# OPTIONS_GHC -O3 -funbox-strict-fields -fvia-C -optc-O3 #-}

import Control.Arrow ((>>>))
import Control.Monad (
    MonadPlus (mplus),
    foldM_,
    forM_,
    guard,
    join,
    replicateM,
    replicateM_,
 )
import qualified Control.Monad as M
import qualified Control.Monad.ST.Strict as ST
import qualified Control.Monad.State.Strict as S
import qualified Control.Monad.Trans.Class as T
import qualified Control.Monad.Trans.Maybe as MT

import qualified Data.Array as A
import qualified Data.Array.MArray.Safe as MA
import qualified Data.Array.IO.Safe as IOA
import qualified Data.Array.ST.Safe as STA
import qualified Data.Array.Unboxed as UA

import Data.Bits
import qualified Data.ByteString.Char8 as B8
import Data.Char
import Data.Int
import Data.Tuple

import Data.Function (on)
import Data.Functor ((<&>))
import Data.Bifunctor (bimap)
import Data.Maybe (fromJust, fromMaybe, isJust)
import qualified Data.Maybe as MB
import Data.Foldable

import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.List   as L
import Data.List (
    elemIndices,
    find,
    findIndices,
    intersect,
    isPrefixOf,
    nub,
    sort,
    sortOn,
 )
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Ix as Ix
import qualified Data.Ratio as R

import Control.Monad.Cont (MonadIO (liftIO))
import Data.IORef (modifyIORef, newIORef, readIORef)
import GHC.IO.Handle (hDuplicateTo)
import System.IO (
    IOMode (ReadMode, WriteMode),
    openFile,
    stdin,
    stdout,
    hFlush
 )
import System.Posix.Internals (puts)
import Text.Printf (printf)
import qualified Data.Array.IO.Safe as UOA

#ifdef DEBUG
import Debug.Trace (trace, traceM, traceShowM)
import Data.Graph (vertices)
debug = flip trace

tracing t x = trace (t ++ " = " ++ show x) x
debugging x t = tracing t x

tracingM t x = traceM $ t ++ " = " ++ show x

#else

debug x _ = x
trace _ x = x
tracing _ x = x
debugging x _ = x

traceM _ = pure ()
tracingM _ _ = pure ()
#endif

readIntB8 :: B8.ByteString -> Int
readIntB8 = B8.readInt >>> (fst . fromJust)

readIntB8s :: B8.ByteString -> [Int]
readIntB8s = B8.words >>> map (B8.readInt >>> (fst . fromJust))

readIntegerB8 :: B8.ByteString -> Integer
readIntegerB8 = B8.readInteger >>> (fst . fromJust)

readIntegerB8s :: B8.ByteString -> [Integer]
readIntegerB8s = B8.words >>> map (B8.readInteger >>> (fst . fromJust))

{-# INLINE modifyArray #-}
{-# SCC modifyArray #-}
modifyArray :: (MA.MArray a e m, MA.Ix i) => a i e -> i -> (e -> e) -> m ()
modifyArray arr ix f = do
    value <- MA.readArray arr ix
    MA.writeArray arr ix $ f value

putsYesNo :: Bool -> IO ()
putsYesNo value = do
    let result :: String =
            if value
                then "YES"
                else "NO"
    printf "%s\n" result

whileM :: (Monad m) => m Bool -> m () -> m ()
whileM f m = do
    t <- f
    M.when t $ do
        m
        whileM f m

iterateWhileM :: (Monad m) => (a -> Bool) -> a -> (a -> m a) -> m [a]
iterateWhileM check x f = do
    y <- f x
    (x:) <$> if check x
        then iterateWhileM check y f
        else M.return []

{- END OF GENERAL -}

type TreeOf a = A.Array Int a
type Tree = TreeOf [Int]
type Edge = (Int, Int)

buildTree :: Int -> [Edge] -> Tree
buildTree n edges = tree
    where
        tree = A.accumArray (flip (:)) [] (1, n) (edges ++ map swap edges)

type JumpTable = A.Array (Int, Int) Int
type State = (JumpTable, TreeOf (Int, Int))

maxK = 17
maxD = 20

preSolve :: Int -> Int -> Tree -> State
preSolve n root tree = ST.runST $ do
    jumpTable <- MA.newArray ((1, 0), (n, maxK)) root :: ST.ST s (STA.STArray s (Int, Int) Int)
    timeRanges <- MA.newArray (1, n) (0, n) :: ST.ST s (STA.STArray s Int (Int, Int))

    -- augh.. learn mfix please
    let dfs arrs v p = flip S.evalStateT 0 $ do
            dfs' arrs v p
        dfs' arrs@(jumpTable, timeRanges) v p = do
            T.lift $ MA.writeArray jumpTable (v, 0) p
            M.forM_ [1 .. maxK] $ \jump -> do
                halfJumpV <- T.lift $ MA.readArray jumpTable (v, jump - 1)
                jumpV <- T.lift $ MA.readArray jumpTable (halfJumpV, jump - 1)
                T.lift $ MA.writeArray jumpTable (v, jump) jumpV

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(_, to) -> (time, to)

            M.forM_ (tree A.! v) $ \u -> do
                M.when (u /= p) $ do
                    dfs' arrs u v

            time <- S.get
            T.lift $ modifyArray timeRanges v $ \(from, _) -> (from, time)

    dfs (jumpTable, timeRanges) root root

    jumpTableA <- STA.freeze jumpTable
    timeRangesA <- STA.freeze timeRanges
    return (jumpTableA, timeRangesA)

{-# INLINE isParent #-}
isParent :: Int -> Int -> TreeOf (Int, Int) -> Bool
isParent u v timeRanges = uFrom <= vFrom && vTo <= uTo
    where
        (uFrom, uTo) = timeRanges A.! u
        (vFrom, vTo) = timeRanges A.! v

lca :: Int -> Int -> State -> Int
lca u v (jumpTable, timeRanges)
    | isParent u v timeRanges = u
    | isParent v u timeRanges = v
    | otherwise = jumpTable A.! (lca', 0)
        where
            liftVertex jump v' = let
                    jumpV' =  jumpTable A.! (v', jump)
                in
                    if isParent jumpV' u timeRanges
                        then v'
                        else jumpV'

            lca' = L.foldr liftVertex v [0 .. maxK]

type STFenwickTree s = STA.STUArray s Int Int

{-# INLINE fenwickAdd #-}
{-# SCC fenwickAdd #-}
fenwickAdd :: STFenwickTree s -> Int -> Int -> Int -> ST.ST s ()
fenwickAdd f i x n = fenwickAdd' i
    where
        fenwickAdd' j = M.when (j <= n) do
            modifyArray f j (+ x)
            fenwickAdd' $ j - (j .|. (- j))

{-# INLINE fenwickGet #-}
{-# SCC fenwickGet #-}
fenwickGet :: STFenwickTree s -> Int -> ST.ST s Int
fenwickGet f i = fenwickGet' i
    where
        fenwickGet' j = if j <= 0
            then pure 0
            else do
                s <- fenwickGet' $ j + (j .|. (- j))
                ds <- MA.readArray f j
                return $ s + ds

data Query = Get Int | Modify Int Int Int Int
    deriving (Show)

solve :: Int -> Tree -> State -> [Query] -> [Int]
solve n tree state@(jumpTable, timeRanges) queries = ST.runST $ do
    let fenwickN = n
    fenwicks <- A.listArray (0, maxD) <$> M.replicateM (maxD + 1) (MA.newArray (1, fenwickN + 10) 0) :: ST.ST s (A.Array Int (STA.STUArray s Int Int))

    answers <- M.forM queries $ \case
        q@(Get v) -> do
            -- let get v level = do
            --         let parent = jumpTable A.! (v, 0)
            --         s <- if level >= maxD
            --             then pure 0
            --             else get parent (level + 1)
            --
            --         let (fromTime, toTime) = timeRanges A.! v
            --         toSum <- fenwickGet (fenwicks A.! level) toTime
            --         fromSum <- fenwickGet (fenwicks A.! level) (fromTime - 1)
            --         return $ s + toSum - fromSum
            -- answer <- get v 0
            let parents = L.take (maxD + 1) . iterate (\v -> jumpTable A.! (v, 0)) $ v
            values <- M.forM (L.zip parents [0..]) $ \(v, level) -> do
                let (fromTime, toTime) = timeRanges A.! v
                toSum <- fenwickGet (fenwicks A.! level) toTime
                fromSum <- fenwickGet (fenwicks A.! level) (fromTime - 1)
                return $ toSum - fromSum
            let answer = sum values
            return $ Just answer

        q@(Modify u v k d) -> do
            let lca' = lca u v state
            let addPath fenwick k v pv = do
                    let (fromV, _) = timeRanges A.! v
                    let (fromPv, _) = timeRanges A.! pv
                    fenwickAdd fenwick fromV k fenwickN
                    fenwickAdd fenwick fromPv (-k) fenwickN
            M.when (lca' /= v) $ addPath (fenwicks A.! d) k v lca'
            M.when (lca' /= u) $ addPath (fenwicks A.! d) k u lca'

            -- let add v level = do
            --         let parent = jumpTable A.! (v, 0)
            --         addPath (fenwicks A.! (d - level)) k v parent
            --         M.when (level < d) $ do
            --             addPath (fenwicks A.! (d - level - 1)) k v parent
            --             add parent (level + 1)
            -- add lca' 0
            let parents = L.take (d + 1) . iterate (\v -> jumpTable A.! (v, 0)) $ lca'
            M.forM_ (L.zip parents [0..]) $ \(v, level) -> do
                let pv = jumpTable A.! (v, 0)
                addPath (fenwicks A.! (d - level)) k v pv
                M.when (d - level > 0) $ addPath (fenwicks A.! (d - level - 1)) k v pv
            return $ Nothing
    return $ MB.catMaybes answers

main :: IO ()
main = do
    n <- B8.getLine <&> readIntB8
    edges <- M.replicateM (n - 1) $ do
        [u, v] <- B8.getLine <&> readIntB8s
        return $ (u, v)

    let verticesCount = n + maxD + 2
        fakeRoot = n + 1
        fakeVertices = [n + 1 .. n + maxD + 2]
        fakeEdges = L.zip (1:fakeVertices) fakeVertices

    let tree = buildTree verticesCount $ edges ++ fakeEdges
    let state = preSolve verticesCount fakeRoot tree

    m <- B8.getLine <&> readIntB8
    queries <- M.replicateM m $ do
        qValues <- B8.getLine <&> readIntB8s
        return $ case qValues of
            [1, v] -> Get v
            [2, u, v, k, d] -> Modify u v k d

    let answers = solve verticesCount tree state queries
    forM_ answers $ printf "%d\n"

{-# LANGUAGE CPP, BlockArguments, DatatypeContexts, DeriveFunctor, GADTs, LambdaCase, RecursiveDo, NumericUnderscores, OverloadedStrings, ScopedTypeVariables, TupleSections #-}
#ifndef DEBUG
{-# LANGUAGE Safe #-}
#endif
{-# LANGUAGE Strict #-}
{-# OPTIONS_GHC -O3 -funbox-strict-fields -fvia-C -optc-O3 #-}

import Control.Arrow ((>>>))
import Control.Monad (
    MonadPlus (mplus),
    foldM_,
    forM_,
    guard,
    join,
    replicateM,
    replicateM_,
 )
import qualified Control.Monad as M
import qualified Control.Monad.ST.Strict as ST
import qualified Control.Monad.State.Strict as S
import qualified Control.Monad.Trans.Class as T
import qualified Control.Monad.Trans.Maybe as MT

import qualified Data.Array as A
import qualified Data.Array.MArray.Safe as MA
import qualified Data.Array.IO.Safe as IOA
import qualified Data.Array.ST.Safe as STA
import qualified Data.Array.Unboxed as UA

import Data.Bits
import qualified Data.ByteString.Char8 as B8
import Data.Char
import Data.Int
import Data.Tuple

import Data.Function (on)
import Data.Functor ((<&>))
import Data.Bifunctor (bimap)
import Data.Maybe (fromJust, fromMaybe, isJust)
import qualified Data.Maybe as MB
import Data.Foldable

import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.List   as L
import Data.List (
    elemIndices,
    find,
    findIndices,
    intersect,
    isPrefixOf,
    nub,
    sort,
    sortOn,
 )
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Ix as Ix
import qualified Data.Ratio as R

import Control.Monad.Cont (MonadIO (liftIO))
import Data.IORef (modifyIORef, newIORef, readIORef)
import GHC.IO.Handle (hDuplicateTo)
import System.IO (
    IOMode (ReadMode, WriteMode),
    openFile,
    stdin,
    stdout,
    hFlush
 )
import System.Posix.Internals (puts)
import Text.Printf (printf)
import qualified Data.Array.IO.Safe as UOA

#ifdef DEBUG
import Debug.Trace (trace, traceM, traceShowM)
import Data.Graph (vertices)
debug = flip trace

tracing t x = trace (t ++ " = " ++ show x) x
debugging x t = tracing t x

tracingM t x = traceM $ t ++ " = " ++ show x

#else

debug x _ = x
trace _ x = x
tracing _ x = x
debugging x _ = x

traceM _ = pure ()
tracingM _ _ = pure ()
#endif

readIntB8 :: B8.ByteString -> Int
readIntB8 = B8.readInt >>> (fst . fromJust)

readIntB8s :: B8.ByteString -> [Int]
readIntB8s = B8.words >>> map (B8.readInt >>> (fst . fromJust))

readIntegerB8 :: B8.ByteString -> Integer
readIntegerB8 = B8.readInteger >>> (fst . fromJust)

readIntegerB8s :: B8.ByteString -> [Integer]
readIntegerB8s = B8.words >>> map (B8.readInteger >>> (fst . fromJust))

{-# INLINE modifyArray #-}
{-# SCC modifyArray #-}
modifyArray :: (MA.MArray a e m, MA.Ix i) => a i e -> i -> (e -> e) -> m ()
modifyArray arr ix f = do
    value <- MA.readArray arr ix
    MA.writeArray arr ix $ f value

putsYesNo :: Bool -> IO ()
putsYesNo value = do
    let result :: String =
            if value
                then "YES"
                else "NO"
    printf "%s\n" result

whileM :: (Monad m) => m Bool -> m () -> m ()
whileM f m = do
    t <- f
    M.when t $ do
        m
        whileM f m

iterateWhileM :: (Monad m) => (a -> Bool) -> a -> (a -> m a) -> m [a]
iterateWhileM check x f = do
    y <- f x
    (x:) <$> if check x
        then iterateWhileM check y f
        else M.return []

{- END OF GENERAL -}

type TreeOf a = A.Array Int a
type Tree = TreeOf [Int]
type Edge = (Int, Int)

buildTree :: Int -> [Edge] -> Tree
buildTree n edges = tree
    where
        tree = A.accumArray (flip (:)) [] (1, n) (edges ++ map swap edges)

type JumpTable = A.Array (Int, Int) Int
type State = (JumpTable, TreeOf (Int, Int))

maxK = 17
maxD = 20

preSolve :: Int -> Int -> Tree -> State
preSolve n root tree = ST.runST $ do
    jumpTable <- MA.newArray ((1, 0), (n, maxK)) root :: ST.ST s (STA.STArray s (Int, Int) Int)
    timeRanges <- MA.newArray (1, n) (0, n) :: ST.ST s (STA.STArray s Int (Int, Int))

    -- augh.. learn mfix please
    let dfs arrs v p = flip S.evalStateT 0 $ do
            dfs' arrs v p
        dfs' arrs@(jumpTable, timeRanges) v p = do
            T.lift $ MA.writeArray jumpTable (v, 0) p
            M.forM_ [1 .. maxK] $ \jump -> do
                halfJumpV <- T.lift $ MA.readArray jumpTable (v, jump - 1)
                jumpV <- T.lift $ MA.readArray jumpTable (halfJumpV, jump - 1)
                T.lift $ MA.writeArray jumpTable (v, jump) jumpV

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(_, to) -> (time, to)

            M.forM_ (tree A.! v) $ \u -> do
                M.when (u /= p) $ do
                    dfs' arrs u v

            time <- S.get
            T.lift $ modifyArray timeRanges v $ \(from, _) -> (from, time)

    dfs (jumpTable, timeRanges) root root

    jumpTableA <- STA.freeze jumpTable
    timeRangesA <- STA.freeze timeRanges
    return (jumpTableA, timeRangesA)

{-# INLINE isParent #-}
isParent :: Int -> Int -> TreeOf (Int, Int) -> Bool
isParent u v timeRanges = uFrom <= vFrom && vTo <= uTo
    where
        (uFrom, uTo) = timeRanges A.! u
        (vFrom, vTo) = timeRanges A.! v

lca :: Int -> Int -> State -> Int
lca u v (jumpTable, timeRanges)
    | isParent u v timeRanges = u
    | isParent v u timeRanges = v
    | otherwise = jumpTable A.! (lca', 0)
        where
            liftVertex jump v' = let
                    jumpV' =  jumpTable A.! (v', jump)
                in
                    if isParent jumpV' u timeRanges
                        then v'
                        else jumpV'

            lca' = L.foldr liftVertex v [0 .. maxK]

type STFenwickTree s = STA.STUArray s Int Int

{-# INLINE fenwickAdd #-}
{-# SCC fenwickAdd #-}
fenwickAdd :: STFenwickTree s -> Int -> Int -> Int -> ST.ST s ()
fenwickAdd f i x n = fenwickAdd' i
    where
        fenwickAdd' j = M.when (j <= n) do
            modifyArray f j (+ x)
            fenwickAdd' $ j - (j .|. (- j))

{-# INLINE fenwickGet #-}
{-# SCC fenwickGet #-}
fenwickGet :: STFenwickTree s -> Int -> ST.ST s Int
fenwickGet f i = fenwickGet' i
    where
        fenwickGet' j = if j > 0
            then pure 0
            else do
                s <- fenwickGet' $ j + (j .|. (- j))
                ds <- MA.readArray f j
                return $ s + ds

data Query = Get Int | Modify Int Int Int Int
    deriving (Show)

solve :: Int -> Tree -> State -> [Query] -> [Int]
solve n tree state@(jumpTable, timeRanges) queries = ST.runST $ do
    let fenwickN = n
    fenwicks <- A.listArray (0, maxD) <$> M.replicateM (maxD + 1) (MA.newArray (1, fenwickN + 10) 0) :: ST.ST s (A.Array Int (STA.STUArray s Int Int))

    answers <- M.forM queries $ \case
        q@(Get v) -> do
            let parents = L.take (maxD + 1) . iterate (\v -> jumpTable A.! (v, 0)) $ v
            values <- M.forM (L.zip parents [0..]) $ \(v, level) -> do
                let (fromTime, toTime) = timeRanges A.! v
                toSum <- fenwickGet (fenwicks A.! level) toTime
                fromSum <- fenwickGet (fenwicks A.! level) (fromTime - 1)
                return $ toSum - fromSum
            let answer = sum values
            return $ Just answer

        q@(Modify u v k d) -> do
            let lca' = lca u v state
            let addPath fenwick k v pv = do
                    let (fromV, _) = timeRanges A.! v
                    let (fromPv, _) = timeRanges A.! pv
                    fenwickAdd fenwick fromV k fenwickN
                    fenwickAdd fenwick fromPv (-k) fenwickN
            M.when (lca' /= v) $ addPath (fenwicks A.! d) k v lca'
            M.when (lca' /= u) $ addPath (fenwicks A.! d) k u lca'

            let parents = L.take (d + 1) . iterate (\v -> jumpTable A.! (v, 0)) $ lca'
            M.forM_ (L.zip parents [0..]) $ \(v, level) -> do
                let pv = jumpTable A.! (v, 0)
                addPath (fenwicks A.! (d - level)) k v pv
                M.when (d - level > 0) $ addPath (fenwicks A.! (d - level - 1)) k v pv
            return $ Nothing
    return $ MB.catMaybes answers

main :: IO ()
main = do
    n <- B8.getLine <&> readIntB8
    edges <- M.replicateM (n - 1) $ do
        [u, v] <- B8.getLine <&> readIntB8s
        return $ (u, v)

    let verticesCount = n + maxD + 2
        fakeRoot = n + 1
        fakeVertices = [n + 1 .. n + maxD + 2]
        fakeEdges = L.zip fakeVertices (L.tail fakeVertices ++ [1])

    let tree = buildTree verticesCount $ edges ++ fakeEdges
    let state = preSolve verticesCount fakeRoot tree

    m <- B8.getLine <&> readIntB8
    queries <- M.replicateM m $ do
        qValues <- B8.getLine <&> readIntB8s
        return $ case qValues of
            [1, v] -> Get v
            [2, u, v, k, d] -> Modify u v k d

    let answers = solve verticesCount tree state queries
    forM_ answers $ printf "%d\n"

{-# LANGUAGE CPP, BlockArguments, DatatypeContexts, DeriveFunctor, GADTs, LambdaCase, RecursiveDo, NumericUnderscores, OverloadedStrings, ScopedTypeVariables, TupleSections #-}
#ifndef DEBUG
{-# LANGUAGE Safe #-}
#endif
{-# LANGUAGE Strict #-}
{-# OPTIONS_GHC -O3 -funbox-strict-fields -fvia-C -optc-O3 #-}

import Control.Arrow ((>>>))
import Control.Monad (
    MonadPlus (mplus),
    foldM_,
    forM_,
    guard,
    join,
    replicateM,
    replicateM_,
 )
import qualified Control.Monad as M
import qualified Control.Monad.ST.Strict as ST
import qualified Control.Monad.State.Strict as S
import qualified Control.Monad.Trans.Class as T
import qualified Control.Monad.Trans.Maybe as MT

import qualified Data.Array as A
import qualified Data.Array.MArray.Safe as MA
import qualified Data.Array.IO.Safe as IOA
import qualified Data.Array.ST.Safe as STA
import qualified Data.Array.Unboxed as UA

import Data.Bits
import qualified Data.ByteString.Char8 as B8
import Data.Char
import Data.Int
import Data.Tuple

import Data.Function (on)
import Data.Functor ((<&>))
import Data.Bifunctor (bimap)
import Data.Maybe (fromJust, fromMaybe, isJust)
import qualified Data.Maybe as MB
import Data.Foldable

import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.List   as L
import Data.List (
    elemIndices,
    find,
    findIndices,
    intersect,
    isPrefixOf,
    nub,
    sort,
    sortOn,
 )
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Ix as Ix
import qualified Data.Ratio as R

import Control.Monad.Cont (MonadIO (liftIO))
import Data.IORef (modifyIORef, newIORef, readIORef)
import GHC.IO.Handle (hDuplicateTo)
import System.IO (
    IOMode (ReadMode, WriteMode),
    openFile,
    stdin,
    stdout,
    hFlush
 )
import System.Posix.Internals (puts)
import Text.Printf (printf)
import qualified Data.Array.IO.Safe as UOA

#ifdef DEBUG
import Debug.Trace (trace, traceM, traceShowM)
import Data.Graph (vertices)
debug = flip trace

tracing t x = trace (t ++ " = " ++ show x) x
debugging x t = tracing t x

tracingM t x = traceM $ t ++ " = " ++ show x

#else

debug x _ = x
trace _ x = x
tracing _ x = x
debugging x _ = x

traceM _ = pure ()
tracingM _ _ = pure ()
#endif

readIntB8 :: B8.ByteString -> Int
readIntB8 = B8.readInt >>> (fst . fromJust)

readIntB8s :: B8.ByteString -> [Int]
readIntB8s = B8.words >>> map (B8.readInt >>> (fst . fromJust))

readIntegerB8 :: B8.ByteString -> Integer
readIntegerB8 = B8.readInteger >>> (fst . fromJust)

readIntegerB8s :: B8.ByteString -> [Integer]
readIntegerB8s = B8.words >>> map (B8.readInteger >>> (fst . fromJust))

modifyArray :: (MA.MArray a e m, MA.Ix i) => a i e -> i -> (e -> e) -> m ()
modifyArray arr ix f = do
    value <- MA.readArray arr ix
    MA.writeArray arr ix $ f value

putsYesNo :: Bool -> IO ()
putsYesNo value = do
    let result :: String =
            if value
                then "YES"
                else "NO"
    printf "%s\n" result

whileM :: (Monad m) => m Bool -> m () -> m ()
whileM f m = do
    t <- f
    M.when t $ do
        m
        whileM f m

iterateWhileM :: (Monad m) => (a -> Bool) -> a -> (a -> m a) -> m [a]
iterateWhileM check x f = do
    y <- f x
    (x:) <$> if check x
        then iterateWhileM check y f
        else M.return []

{- END OF GENERAL -}

type TreeOf a = A.Array Int a
type Tree = TreeOf [Int]
type Edge = (Int, Int)

buildTree :: Int -> [Edge] -> Tree
buildTree n edges = tree
    where
        tree = A.accumArray (flip (:)) [] (1, n) (edges ++ map swap edges)

type JumpTable = A.Array (Int, Int) (Maybe Int)
type State = (JumpTable, TreeOf (Int, Int))

maxK = 19
maxD = 20

preSolve :: Int -> Int -> Tree -> State
preSolve n root tree = ST.runST $ do
    jumpTable <- MA.newArray ((1, 0), (n, maxK)) Nothing :: ST.ST s (STA.STArray s (Int, Int) (Maybe Int))
    timeRanges <- MA.newArray (1, n) (0, 2 * n) :: ST.ST s (STA.STArray s Int (Int, Int))

    -- augh.. learn mfix please
    let dfs arrs v p = flip S.evalStateT 0 $ do
            dfs' arrs v p
        dfs' arrs@(jumpTable, timeRanges) v p = do
            tracingM "+dfs' v p" $ (v, p)
            T.lift $ MA.writeArray jumpTable (v, 0) p
            M.forM_ [1 .. maxK] $ \jump -> do
                jumpV <- MT.runMaybeT $ do
                    halfJumpV <- MT.MaybeT . T.lift $ MA.readArray jumpTable (v, jump - 1)
                    MT.MaybeT . T.lift $ MA.readArray jumpTable (halfJumpV, jump - 1)
                T.lift $ MA.writeArray jumpTable (v, jump) jumpV

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(_, to) -> (time, to)

            M.forM_ (tree A.! v) $ \u -> do
                M.when (Just u /= p) $ do
                    dfs' arrs u $ Just v

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(from, _) -> (from, time)
            tracingM "- dfs' v p" $ (v, p)

    dfs (jumpTable, timeRanges) root Nothing

    jumpTableA <- STA.freeze jumpTable
    timeRangesA <- STA.freeze timeRanges
    return (jumpTableA, timeRangesA)

isParent :: Int -> Int -> TreeOf (Int, Int) -> Bool
isParent u v timeRanges = uFrom <= vFrom && vTo <= uTo
    where
        (uFrom, uTo) = timeRanges A.! u
        (vFrom, vTo) = timeRanges A.! v

lca :: Int -> Int -> State -> Int
lca u v (jumpTable, timeRanges)
    | isParent u v timeRanges = u
    | isParent v u timeRanges = v
    | otherwise = MB.fromJust $ jumpTable A.! (lca', 0)
        where
            liftVertex jump v' = MB.fromMaybe v' $ do
                jumpV' <- jumpTable A.! (v', jump)
                M.guard $ not $ isParent jumpV' u timeRanges
                return $ jumpV'

            lca' = L.foldr liftVertex v [0 .. maxK]

type STFenwickTree s = STA.STUArray s Int Int64

fenwickAdd :: STFenwickTree s -> Int -> Int64 -> Int -> ST.ST s ()
fenwickAdd f i x n = do
    M.forM_ (takeWhile (<= n) $ iterate (\j -> j - (j .|. (- j))) i) $ \j -> do
        modifyArray f j (+ x)

fenwickGet :: STFenwickTree s -> Int -> ST.ST s Int64
fenwickGet f i = do
    values <- M.forM (takeWhile (> 0) $ iterate (\j -> j + (j .|. (- j))) i) $ \j -> do
        MA.readArray f j
    return $ sum values

data Query = Get Int | Modify Int Int Int Int
    deriving (Show)

solve :: Int -> Tree -> State -> [Query] -> [Int64]
solve n tree state@(jumpTable, timeRanges) queries = ST.runST $ do
    let fenwickN = 2 * n
    fenwicks <- A.listArray (0, maxD) <$> M.replicateM (maxD + 1) (MA.newArray (1, fenwickN + 10) 0) :: ST.ST s (A.Array Int (STA.STUArray s Int Int64))

    answers <- M.forM queries $ \case
        q@(Get v) -> do
            tracingM "Get v" $ q
            let parents = MB.catMaybes . L.take maxD . iterate (M.>>= (\v -> jumpTable A.! (v, 0))) $ Just v
            values <- M.forM (L.zip parents [0..]) $ \(v, level) -> do
                let (fromTime, toTime) = timeRanges A.! v
                toSum <- fenwickGet (fenwicks A.! level) toTime
                fromSum <- fenwickGet (fenwicks A.! level) (fromTime - 1)
                tracingM "answer += (v, level, +x)" $ (v, level, toSum - fromSum)
                return $ toSum - fromSum
            let answer = sum values
            tracingM "answer" $ answer
            return $ Just answer

        q@(Modify u v k' d) -> do
            let k = fromIntegral k'
            tracingM "Modify u v k d" $ q
            let lca' = lca u v state
            tracingM "lca'" $ lca'
            let addPath fenwicks d k v Nothing = do
                    tracingM "addFromRoot d k v" $ (d, k, v)
                    let (fromV, _) = timeRanges A.! v
                    fenwickAdd (fenwicks A.! d) fromV k fenwickN
                addPath fenwicks d k v (Just pv) = do
                    tracingM "addPath d k v pv" $ (d, k, v, pv)
                    addPath fenwicks d k v Nothing
                    addPath fenwicks d (-k) pv Nothing
            M.when (lca' /= v) $ addPath fenwicks d k v $ Just lca'
            M.when (lca' /= u) $ addPath fenwicks d k u $ Just lca'

            let parents = MB.catMaybes . L.take (d + 1) . iterate (M.>>= (\v -> jumpTable A.! (v, 0))) $ Just lca'
            M.forM (L.zip parents [0..]) $ \(v, level) -> do
                tracingM "iterating up (v, level)" $ (v, level)
                let pv = jumpTable A.! (v, 0)
                tracingM "v, pv, d - level" $ (v, pv, d - level)
                addPath fenwicks (d - level) k v pv
                M.when (d - level > 0) $ addPath fenwicks (d - level - 1) k v pv
            return $ Nothing
    return $ MB.catMaybes answers

main :: IO ()
main = do
    n <- B8.getLine <&> readIntB8
    edges <- M.replicateM (n - 1) $ do
        [u, v] <- B8.getLine <&> readIntB8s
        return $ (u, v)

    let verticesCount = n + maxD
        fakeRoot = n + 1
        fakeVertices = [n + 1 .. n + maxD]
        fakeEdges = L.zip fakeVertices (L.tail fakeVertices ++ [1])

    let tree = buildTree verticesCount $ edges ++ fakeEdges
    let state = preSolve verticesCount fakeRoot tree

    m <- B8.getLine <&> readIntB8
    queries <- M.replicateM m $ do
        qValues <- B8.getLine <&> readIntB8s
        return $ case qValues of
            [1, v] -> Get v
            [2, u, v, k, d] -> Modify u v k d

    let answers = solve verticesCount tree state queries
    forM_ answers $ printf "%d\n"

{-# LANGUAGE CPP, BlockArguments, DatatypeContexts, DeriveFunctor, GADTs, LambdaCase, RecursiveDo, NumericUnderscores, OverloadedStrings, ScopedTypeVariables, TupleSections #-}
#ifndef DEBUG
{-# LANGUAGE Safe #-}
#endif
{-# LANGUAGE Strict #-}
{-# OPTIONS_GHC -O3 -funbox-strict-fields -fvia-C -optc-O3 #-}

import Control.Arrow ((>>>))
import Control.Monad (
    MonadPlus (mplus),
    foldM_,
    forM_,
    guard,
    join,
    replicateM,
    replicateM_,
 )
import qualified Control.Monad as M
import qualified Control.Monad.ST.Strict as ST
import qualified Control.Monad.State.Strict as S
import qualified Control.Monad.Trans.Class as T
import qualified Control.Monad.Trans.Maybe as MT

import qualified Data.Array as A
import qualified Data.Array.MArray.Safe as MA
import qualified Data.Array.IO.Safe as IOA
import qualified Data.Array.ST.Safe as STA
import qualified Data.Array.Unboxed as UA

import Data.Bits
import qualified Data.ByteString.Char8 as B8
import Data.Char
import Data.Int
import Data.Tuple

import Data.Function (on)
import Data.Functor ((<&>))
import Data.Bifunctor (bimap)
import Data.Maybe (fromJust, fromMaybe, isJust)
import qualified Data.Maybe as MB
import Data.Foldable

import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.List   as L
import Data.List (
    elemIndices,
    find,
    findIndices,
    intersect,
    isPrefixOf,
    nub,
    sort,
    sortOn,
 )
import qualified Data.Map as M
import qualified Data.Set as S
import qualified Data.Ix as Ix
import qualified Data.Ratio as R

import Control.Monad.Cont (MonadIO (liftIO))
import Data.IORef (modifyIORef, newIORef, readIORef)
import GHC.IO.Handle (hDuplicateTo)
import System.IO (
    IOMode (ReadMode, WriteMode),
    openFile,
    stdin,
    stdout,
    hFlush
 )
import System.Posix.Internals (puts)
import Text.Printf (printf)
import qualified Data.Array.IO.Safe as UOA

#ifdef DEBUG
import Debug.Trace (trace, traceM, traceShowM)
import Data.Graph (vertices)
debug = flip trace

tracing t x = trace (t ++ " = " ++ show x) x
debugging x t = tracing t x

tracingM t x = traceM $ t ++ " = " ++ show x

#else

debug x _ = x
trace _ x = x
tracing _ x = x
debugging x _ = x

traceM _ = pure ()
tracingM _ _ = pure ()
#endif

readIntB8 :: B8.ByteString -> Int
readIntB8 = B8.readInt >>> (fst . fromJust)

readIntB8s :: B8.ByteString -> [Int]
readIntB8s = B8.words >>> map (B8.readInt >>> (fst . fromJust))

readIntegerB8 :: B8.ByteString -> Integer
readIntegerB8 = B8.readInteger >>> (fst . fromJust)

readIntegerB8s :: B8.ByteString -> [Integer]
readIntegerB8s = B8.words >>> map (B8.readInteger >>> (fst . fromJust))

modifyArray :: (MA.MArray a e m, MA.Ix i) => a i e -> i -> (e -> e) -> m ()
modifyArray arr ix f = do
    value <- MA.readArray arr ix
    MA.writeArray arr ix $ f value

putsYesNo :: Bool -> IO ()
putsYesNo value = do
    let result :: String =
            if value
                then "YES"
                else "NO"
    printf "%s\n" result

whileM :: (Monad m) => m Bool -> m () -> m ()
whileM f m = do
    t <- f
    M.when t $ do
        m
        whileM f m

iterateWhileM :: (Monad m) => (a -> Bool) -> a -> (a -> m a) -> m [a]
iterateWhileM check x f = do
    y <- f x
    (x:) <$> if check x
        then iterateWhileM check y f
        else M.return []

{- END OF GENERAL -}

type TreeOf a = A.Array Int a
type Tree = TreeOf [Int]
type Edge = (Int, Int)

buildTree :: Int -> [Edge] -> Tree
buildTree n edges = tree
    where
        tree = A.accumArray (flip (:)) [] (1, n) (edges ++ map swap edges)

type JumpTable = A.Array (Int, Int) (Maybe Int)
type State = (JumpTable, TreeOf (Int, Int))

maxK = 19
maxD = 20

preSolve :: Int -> Int -> Tree -> State
preSolve n root tree = ST.runST $ do
    jumpTable <- MA.newArray ((1, 0), (n, maxK)) Nothing :: ST.ST s (STA.STArray s (Int, Int) (Maybe Int))
    timeRanges <- MA.newArray (1, n) (0, 2 * n) :: ST.ST s (STA.STArray s Int (Int, Int))

    -- augh.. learn mfix please
    let dfs arrs v p = flip S.evalStateT 0 $ do
            dfs' arrs v p
        dfs' arrs@(jumpTable, timeRanges) v p = do
            tracingM "+dfs' v p" $ (v, p)
            T.lift $ MA.writeArray jumpTable (v, 0) p
            M.forM_ [1 .. maxK] $ \jump -> do
                jumpV <- MT.runMaybeT $ do
                    halfJumpV <- MT.MaybeT . T.lift $ MA.readArray jumpTable (v, jump - 1)
                    MT.MaybeT . T.lift $ MA.readArray jumpTable (halfJumpV, jump - 1)
                T.lift $ MA.writeArray jumpTable (v, jump) jumpV

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(_, to) -> (time, to)

            M.forM_ (tree A.! v) $ \u -> do
                M.when (Just u /= p) $ do
                    dfs' arrs u $ Just v

            time <- S.modify' (+ 1) >> S.get
            T.lift $ modifyArray timeRanges v $ \(from, _) -> (from, time)
            tracingM "- dfs' v p" $ (v, p)

    dfs (jumpTable, timeRanges) root Nothing

    jumpTableA <- STA.freeze jumpTable
    timeRangesA <- STA.freeze timeRanges
    return (jumpTableA, timeRangesA)

isParent :: Int -> Int -> TreeOf (Int, Int) -> Bool
isParent u v timeRanges = uFrom <= vFrom && vTo <= uTo
    where
        (uFrom, uTo) = timeRanges A.! u
        (vFrom, vTo) = timeRanges A.! v

lca :: Int -> Int -> State -> Int
lca u v (jumpTable, timeRanges)
    | isParent u v timeRanges = u
    | isParent v u timeRanges = v
    | otherwise = MB.fromJust $ jumpTable A.! (lca', 0)
        where
            liftVertex jump v' = MB.fromMaybe v' $ do
                jumpV' <- jumpTable A.! (v', jump)
                M.guard $ not $ isParent jumpV' u timeRanges
                return $ jumpV'

            lca' = L.foldr liftVertex v [0 .. maxK]

type STFenwickTree s = STA.STUArray s Int Int

fenwickAdd :: STFenwickTree s -> Int -> Int -> Int -> ST.ST s ()
fenwickAdd f i x n = do
    M.forM_ (takeWhile (<= n) $ iterate (\j -> j - (j .|. (- j))) i) $ \j -> do
        modifyArray f j (+ x)

fenwickGet :: STFenwickTree s -> Int -> ST.ST s Int
fenwickGet f i = do
    values <- M.forM (takeWhile (> 0) $ iterate (\j -> j + (j .|. (- j))) i) $ \j -> do
        MA.readArray f j
    return $ sum values

data Query = Get Int | Modify Int Int Int Int
    deriving (Show)

solve :: Int -> Tree -> State -> [Query] -> [Int]
solve n tree state@(jumpTable, timeRanges) queries = ST.runST $ do
    let fenwickN = 2 * n
    fenwicks <- A.listArray (0, maxD) <$> M.replicateM (maxD + 1) (MA.newArray (1, fenwickN + 10) 0) :: ST.ST s (A.Array Int (STA.STUArray s Int Int))

    answers <- M.forM queries $ \case
        q@(Get v) -> do
            tracingM "Get v" $ q
            let parents = MB.catMaybes . L.take maxD . iterate (M.>>= (\v -> jumpTable A.! (v, 0))) $ Just v
            values <- M.forM (L.zip parents [0..]) $ \(v, level) -> do
                let (fromTime, toTime) = timeRanges A.! v
                toSum <- fenwickGet (fenwicks A.! level) toTime
                fromSum <- fenwickGet (fenwicks A.! level) (fromTime - 1)
                tracingM "answer += (v, level, +x)" $ (v, level, toSum - fromSum)
                return $ toSum - fromSum
            let answer = sum values
            tracingM "answer" $ answer
            return $ Just answer

        q@(Modify u v k d) -> do
            tracingM "Modify u v k d" $ q
            let lca' = lca u v state
            tracingM "lca'" $ lca'
            let addPath fenwicks d k v Nothing = do
                    tracingM "addFromRoot d k v" $ (d, k, v)
                    let (fromV, _) = timeRanges A.! v
                    fenwickAdd (fenwicks A.! d) fromV k fenwickN
                addPath fenwicks d k v (Just pv) = do
                    tracingM "addPath d k v pv" $ (d, k, v, pv)
                    addPath fenwicks d k v Nothing
                    addPath fenwicks d (-k) pv Nothing
            M.when (lca' /= v) $ addPath fenwicks d k v $ Just lca'
            M.when (lca' /= u) $ addPath fenwicks d k u $ Just lca'

            let parents = MB.catMaybes . L.take (d + 1) . iterate (M.>>= (\v -> jumpTable A.! (v, 0))) $ Just lca'
            M.forM (L.zip parents [0..]) $ \(v, level) -> do
                tracingM "iterating up (v, level)" $ (v, level)
                let pv = jumpTable A.! (v, 0)
                tracingM "v, pv, d - level" $ (v, pv, d - level)
                addPath fenwicks (d - level) k v pv
                M.when (d - level > 0) $ addPath fenwicks (d - level - 1) k v pv
            return $ Nothing
    return $ MB.catMaybes answers

main :: IO ()
main = do
    n <- B8.getLine <&> readIntB8
    edges <- M.replicateM (n - 1) $ do
        [u, v] <- B8.getLine <&> readIntB8s
        return $ (u, v)

    let verticesCount = n + maxD
        fakeRoot = n + 1
        fakeVertices = [n + 1 .. n + maxD]
        fakeEdges = L.zip fakeVertices (L.tail fakeVertices ++ [1])

    let tree = buildTree verticesCount $ edges ++ fakeEdges
    let state = preSolve verticesCount fakeRoot tree

    m <- B8.getLine <&> readIntB8
    queries <- M.replicateM m $ do
        qValues <- B8.getLine <&> readIntB8s
        return $ case qValues of
            [1, v] -> Get v
            [2, u, v, k, d] -> Modify u v k d

    let answers = solve verticesCount tree state queries
    forM_ answers $ printf "%d\n"