module Main where import Control.Monad (unless) import Control.Monad.Fix (fix) import Data.List (find, findIndex) import Data.Maybe (isJust) import Data.Array.IArray (Array, listArray, (!)) import qualified Data.Set as S data Vehicle = Vehicle { identifier :: Int, cool :: Int } deriving Show instance Eq Vehicle where (==) (Vehicle i _) (Vehicle j _) = i == j instance Ord Vehicle where compare (Vehicle i _) (Vehicle j _) = compare i j dropAt :: Int -> [a] -> [a] dropAt = f 0 where f i t (x:xs) | i == t = xs | otherwise = x : f (succ i) t xs f _ _ _ = [] memberBy :: Ord a => (a -> Bool) -> S.Set a -> Bool memberBy = (.) isJust . flip (.) S.toList . find lookupBy :: Ord a => (a -> Bool) -> S.Set a -> Maybe a lookupBy = flip (.) S.toList . find findSetIndexVehicle :: Int -> [S.Set Vehicle] -> Maybe Int findSetIndexVehicle i = findIndex (memberBy ((==i) . identifier)) lookupVehicle :: Int -> S.Set Vehicle -> Maybe Vehicle lookupVehicle i = lookupBy ((==i) . identifier) connect :: Int -> [S.Set Vehicle] -> [S.Set Vehicle] connect i vs = flip (maybe vs) (findSetIndexVehicle i vs) $ \xi -> let dx = dropAt xi vs in flip (maybe vs) (findSetIndexVehicle (succ i) dx) $ \yi -> (vs !! xi) `S.union` (dx !! yi) : dropAt yi dx separate :: Int -> [S.Set Vehicle] -> [S.Set Vehicle] separate i vs = flip (maybe vs) (findSetIndexVehicle i vs) $ \xi -> let x = vs !! xi in flip (maybe vs) (lookupVehicle (succ i) x) $ \x1 -> [S.delete x1 x, S.singleton x1] ++ dropAt xi vs remodel :: Int -> [S.Set Vehicle] -> [S.Set Vehicle] remodel i vs = flip (maybe vs) (findSetIndexVehicle i vs) $ \xi -> let x = vs !! xi in flip (maybe vs) (lookupVehicle i x) $ \y -> S.insert (y { cool = succ (cool y) }) x : dropAt xi vs attractiveness :: Int -> [S.Set Vehicle] -> Maybe Int attractiveness i vs = flip (maybe Nothing) (findSetIndexVehicle i vs) $ Just . foldr ((+) . cool) 0 . S.toList . (vs !!) main :: IO () main = let queryMap = listArray (1, 3) [connect, separate, remodel] :: Array Int (Int -> [S.Set Vehicle] -> [S.Set Vehicle]) in do [n, q] <- map (read :: String -> Int) . words <$> getLine as <- zipWith ((.) S.singleton . (flip (.) read . Vehicle)) [1..n] . words <$> getLine ($ (q, as)) . fix $ \f (i, a) -> unless (i == 0) $ do [qy, xi] <- map read . words <$> getLine if qy > 3 then maybe (return ()) ((<*) (f (pred i, a)) . print) (attractiveness xi a) else f (pred i, (queryMap ! qy) xi a)