{-# LANGUAGE DerivingVia #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_HADDOCK hide #-} -- | Base module for implementing dynamic sequences. It internaly uses a splay tree and user has to -- track the root node change. -- -- @since 1.2.0.0 module AtCoder.Extra.Seq.Raw ( -- * Seq Seq (..), -- * Constructors newST, resetST, newNodeST, newSeqST, freeNodeST, freeSubtreeST, -- * Metadata capacity, lengthST, -- * Merge/split mergeST, merge3ST, merge4ST, splitST, split3ST, split4ST, splitLrST, sliceST, -- * Read/write readST, readMaybeST, writeST, modifyST, exchangeST, -- * Products prodST, prodMaybeST, prodAllST, -- * Applications applyInST, applyToRootST, reverseST, -- * Insert/delete insertST, deleteST, deleteST_, detachST, -- * Balancing rotateST, splayST, splayKthST, -- * Bisection methods -- ** C++-like ilowerBoundST, ilowerBoundM, ilowerBoundProdST, ilowerBoundProdM, -- ** Splits isplitMaxRightST, isplitMaxRightM, isplitMaxRightProdST, isplitMaxRightProdM, -- ** Max right imaxRightST, imaxRightM, imaxRightProdST, imaxRightProdM, -- * Conversions freezeST, -- * Internals -- | These functions are exported primarily for @Map@ implementations. splitMaxRightWithST, maxRightWithST, updateNodeST, writeNodeST, modifyNodeST, exchangeNodeST, propNodeST, applyNodeST, ) where import AtCoder.Extra.Pool qualified as P import AtCoder.Internal.Assert qualified as ACIA import AtCoder.LazySegTree (SegAct (..)) import Control.Monad (unless, when) import Control.Monad.Primitive (PrimMonad, PrimState, stToPrim) import Control.Monad.ST (ST) import Data.Bit import Data.Bits hiding (rotate) import Data.Coerce (coerce) import Data.Vector.Generic qualified as VG import Data.Vector.Generic.Mutable qualified as VGM import Data.Vector.Unboxed qualified as VU import Data.Vector.Unboxed.Mutable qualified as VUM import GHC.Stack (HasCallStack) import Prelude hiding (seq) -- | Storages of dynamic sequences of monoid values with monoid actions on them through the `SegAct` -- instance. -- -- @since 1.2.0.0 data Seq s f a = Seq { -- | The maximum number of elements. -- -- @since 1.2.0.0 nSeq :: {-# UNPACK #-} !Int, -- | `Pool` for free slot management. -- -- @since 1.2.0.0 poolSeq :: !(P.Pool s ()), -- | Decomposed node data storage: left children. -- -- @since 1.2.0.0 lSeq :: !(VUM.MVector s P.Index), -- | Decomposed node data storage: right children. -- -- @since 1.2.0.0 rSeq :: !(VUM.MVector s P.Index), -- | Decomposed node data storage: parents. -- -- @since 1.2.0.0 pSeq :: !(VUM.MVector s P.Index), -- | Decomposed node data storage: subtree sizes. -- -- @since 1.2.0.0 sSeq :: !(VUM.MVector s Int), -- | Decomposed node data storage: monoid values. -- -- @since 1.2.0.0 vSeq :: !(VUM.MVector s a), -- | Decomposed node data storage: monoid products. -- -- @since 1.2.0.0 prodSeq :: !(VUM.MVector s a), -- | Decomposed node data storage: reversed flag of children. -- -- @since 1.2.0.0 revSeq :: !(VUM.MVector s Bit), -- | Decomposed node data storage: lazily propagated monoid action. Use @()@ if you don't need -- monoid actions. -- -- @since 1.2.0.0 lazySeq :: !(VUM.MVector s f) } -- | \(O(n)\) Creates a new `Seq` of length \(n\). -- -- @since 1.2.0.0 {-# INLINEABLE newST #-} newST :: (Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Int -> ST s (Seq s f a) newST nSeq = do poolSeq <- P.new nSeq lSeq <- VUM.unsafeNew nSeq rSeq <- VUM.unsafeNew nSeq pSeq <- VUM.unsafeNew nSeq sSeq <- VUM.unsafeNew nSeq vSeq <- VUM.unsafeNew nSeq prodSeq <- VUM.unsafeNew nSeq revSeq <- VUM.unsafeNew nSeq lazySeq <- VUM.unsafeNew nSeq pure Seq {..} -- | \(O(1)\) Clears the sequence storage. -- -- @since 1.2.0.0 {-# INLINE resetST #-} resetST :: Seq s f a -> ST s () resetST Seq {poolSeq} = stToPrim $ P.clear poolSeq -- | \(O(1)\) Allocates a new sequence of length \(1\). -- -- @since 1.2.0.0 {-# INLINEABLE newNodeST #-} newNodeST :: (HasCallStack, Monoid f, VU.Unbox f, VU.Unbox a) => Seq s f a -> a -> ST s P.Index newNodeST Seq {..} x = do i <- P.alloc poolSeq () VGM.write lSeq (coerce i) P.undefIndex VGM.write rSeq (coerce i) P.undefIndex VGM.write pSeq (coerce i) P.undefIndex VGM.write sSeq (coerce i) 1 VGM.write vSeq (coerce i) x VGM.write prodSeq (coerce i) x VGM.write revSeq (coerce i) $ Bit False VGM.write lazySeq (coerce i) mempty pure i -- | \(O(n)\) Allocates a new sequence. -- -- @since 1.2.0.0 {-# INLINEABLE newSeqST #-} newSeqST :: (HasCallStack, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> VU.Vector a -> ST s P.Index newSeqST seq@Seq {..} !xs = do -- [l, r) let inner l r | l >= r = pure P.undefIndex | l + 1 == r = newNodeST seq $ xs VG.! l | otherwise = do let !m = (l + r) `div` 2 rootL <- inner l m root <- newNodeST seq (xs VG.! m) rootR <- inner (m + 1) r unless (P.nullIndex rootL) $ do VGM.write lSeq (coerce root) rootL VGM.write pSeq (coerce rootL) root unless (P.nullIndex rootR) $ do VGM.write rSeq (coerce root) rootR VGM.write pSeq (coerce rootR) root updateNodeST seq root pure root inner 0 (VU.length xs) -- | \(O(1)\) Frees a node. -- -- @since 1.2.0.0 {-# INLINE freeNodeST #-} freeNodeST :: Seq s v a -> P.Index -> ST s () freeNodeST Seq {poolSeq} = P.free poolSeq -- | \(O(n)\) Frees a subtree. -- -- @since 1.2.0.0 {-# INLINEABLE freeSubtreeST #-} freeSubtreeST :: (VU.Unbox a) => Seq s f a -> P.Index -> ST s () freeSubtreeST Seq {lSeq, rSeq, poolSeq} c0 | P.nullIndex c0 = pure () | otherwise = do let inner c = do cl <- VGM.read lSeq (coerce c) unless (P.nullIndex cl) (inner cl) cr <- VGM.read rSeq (coerce c) unless (P.nullIndex cr) (inner cr) inner c0 P.free poolSeq c0 -- ------------------------------------------------------------------------------------------------- -- Metadata -- ------------------------------------------------------------------------------------------------- -- | \(O(1)\) Returns the capacity of the sequence storage. -- -- @since 1.2.1.0 {-# INLINE capacity #-} capacity :: Seq s f a -> Int capacity = nSeq -- | \(O(1)\) Returns the length of a sequence or a subtree. -- -- @since 1.2.1.0 {-# INLINE lengthST #-} lengthST :: Seq s f a -> P.Index -> ST s Int lengthST Seq {..} i | P.nullIndex i = pure 0 | otherwise = VGM.read sSeq (coerce i) -- ------------------------------------------------------------------------------------------------- -- Merge/split -- ------------------------------------------------------------------------------------------------- {-# INLINE assertRootST #-} assertRootST :: (HasCallStack) => Seq s f a -> P.Index -> ST s () assertRootST Seq {pSeq} i = do p <- VGM.read pSeq (coerce i) let !_ = ACIA.runtimeAssert (P.nullIndex p) $ "AtCoder.Extra.Seq.Raw.assertRootST: not a root (node `" ++ show i ++ "`, parent `" ++ show p ++ "`)" pure () {-# INLINE assertRootOrNullST #-} assertRootOrNullST :: (HasCallStack) => Seq s f a -> P.Index -> ST s () assertRootOrNullST Seq {pSeq} i | P.nullIndex i = pure () | otherwise = do p <- VGM.read pSeq (coerce i) let !_ = ACIA.runtimeAssert (P.nullIndex p) $ "AtCoder.Extra.Seq.Raw.assertRootOrNullST: not a root (node `" ++ show i ++ "`, parent `" ++ show p ++ "`)" pure () -- | Amortized \(O(\log n)\). Merges two sequences \(l, r\) into one in the given order, ignoring -- empty sequences. -- -- ==== Constraints -- - The vertices must be either null or a root. -- -- @since 1.2.0.0 {-# INLINEABLE mergeST #-} mergeST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> P.Index -> ST s P.Index mergeST seq@Seq {pSeq, lSeq} lRoot rRoot | P.nullIndex lRoot = pure rRoot | P.nullIndex rRoot = pure lRoot | otherwise = do assertRootST seq lRoot assertRootST seq rRoot rRoot' <- splayKthST seq rRoot 0 VGM.write lSeq (coerce rRoot') lRoot VGM.write pSeq (coerce lRoot) rRoot' updateNodeST seq rRoot' pure rRoot' -- | Amortized \(O(\log n)\). Merges three sequences \(l, m, r\) into one in the given order, -- ignoring empty sequences. -- -- ==== Constraints -- - The vertices must be either null or a root. -- -- @since 1.2.0.0 {-# INLINE merge3ST #-} merge3ST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> P.Index -> P.Index -> ST s P.Index merge3ST seq a b c = do r' <- mergeST seq a b mergeST seq r' c -- | Amortized \(O(\log n)\). Merges four sequences \(l, b, c, d, m, r\) into one in the given -- order, ignoring empty sequences. -- -- ==== Constraints -- - The vertices must be either null or a root. -- -- @since 1.2.0.0 {-# INLINE merge4ST #-} merge4ST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> P.Index -> P.Index -> P.Index -> ST s P.Index merge4ST seq a b c d = do r' <- mergeST seq a b r'' <- mergeST seq r' c mergeST seq r'' d -- | Amortized \(O(\log n)\). Splits a sequences into two: \([0, k), [k, n)\). -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le k \le n\). -- -- @since 1.2.0.0 {-# INLINEABLE splitST #-} splitST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s (P.Index, P.Index) splitST seq@Seq {..} root k = do assertRootOrNullST seq root if k == 0 then pure (P.undefIndex, root) else do size <- VGM.read sSeq $ coerce root if k == size then pure (root, P.undefIndex) else do root' <- splayKthST seq root (k - 1) r <- VGM.exchange rSeq (coerce root') P.undefIndex VGM.write pSeq (coerce r) P.undefIndex updateNodeST seq root' pure (root', r) -- | Amortized \(O(\log n)\). Splits a sequences into three: \([0, l), [l, r), [r, n)\). -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le l \le r \le n\). -- -- @since 1.2.0.0 {-# INLINE split3ST #-} split3ST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> ST s (P.Index, P.Index, P.Index) split3ST seq root l r = do (!root', !c) <- splitST seq root r (!a, !b) <- splitST seq root' l pure (a, b, c) -- | Amortized \(O(\log n)\). Splits a sequences into four: \([0, i), [i, j), [j, k), [k, n)\). -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le i \le j \le k \le n\). -- -- @since 1.2.0.0 {-# INLINE split4ST #-} split4ST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> Int -> ST s (P.Index, P.Index, P.Index, P.Index) split4ST seq root i j k = do (!root', !d) <- splitST seq root k (!root'', !c) <- splitST seq root' j (!a, !b) <- splitST seq root'' i pure (a, b, c, d) -- | Amortized \(O(\log n)\). Splits a sequence into three: \([0, \mathrm{root}), \mathrm{root}, [\mathrm{root} + 1, n)\). -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINEABLE splitLrST #-} splitLrST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> ST s (P.Index, P.Index, P.Index) splitLrST seq@Seq {..} root = do assertRootST seq root s <- do rootL <- VGM.read lSeq (coerce root) if P.nullIndex rootL then pure 0 else VGM.read sSeq (coerce rootL) split3ST seq root s (s + 1) -- | Amortized \(O(\log n)\). Captures the root of a subtree of \([l, r)\). Splay the new root after -- call. -- -- ==== Constraints -- - \(0 \le \lt r \le n\). Note that the interval must have positive length. -- -- @since 1.2.0.0 {-# INLINEABLE sliceST #-} sliceST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> ST s P.Index sliceST seq@Seq {..} root l r | l == 0 = do size <- VGM.read sSeq (coerce root) if r == size then pure root else do root' <- splayKthST seq root r VGM.read lSeq $ coerce root' | otherwise = do size <- VGM.read sSeq $ coerce root if r == size then do root' <- splayKthST seq root (l - 1) VGM.read rSeq $ coerce root' else do -- o--l--o--o--r--o -- [ ) -- * root' (splayed) -- * rootL (detached from the root) -- \* rootL' (splayed) -- * right(rootL'): node that corresponds to [l, r) root' <- splayKthST seq root r rootL <- VGM.read lSeq $ coerce root' -- detach `rootL` from `root'` VGM.write pSeq (coerce rootL) P.undefIndex rootL' <- splayKthST seq rootL (l - 1) -- re-attach `rootL'` to `root'` VGM.write pSeq (coerce rootL') root' VGM.write lSeq (coerce root') rootL' updateNodeST seq root' VGM.read rSeq $ coerce rootL' -- ------------------------------------------------------------------------------------------------- -- Modifications -- ------------------------------------------------------------------------------------------------- -- | Amortized \(O(\log n)\). Reads the \(k\)-th node's monoid value. -- -- ==== Constraints -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE readST #-} readST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s (a, P.Index) readST seq@Seq {..} root k = do assertRootST seq root root' <- splayKthST seq root k (,root') <$> VGM.read vSeq (coerce root') -- | Amortized \(O(\log n)\). Reads the \(k\)-th node's monoid value. -- -- ==== Constraints -- - The root must be empty or a root. -- -- @since 1.2.0.0 {-# INLINEABLE readMaybeST #-} readMaybeST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s (Maybe (a, P.Index)) readMaybeST seq@Seq {..} root k | P.nullIndex root = pure Nothing | otherwise = do assertRootST seq root s <- VGM.read sSeq (coerce root) if 0 <= k && k < s then do root' <- splayKthST seq root k Just . (,root') <$> VGM.read vSeq (coerce root') else pure Nothing -- | Amortized \(O(\log n)\). Writes to the \(k\)-th node's monoid value. -- -- ==== Constraints -- - The node must be a root. -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE writeST #-} writeST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> a -> ST s P.Index writeST seq root k v = do assertRootST seq root root' <- splayKthST seq root k writeNodeST seq root' v pure root' -- | Amortized \(O(\log n)\). Modifies the \(k\)-th node's monoid value. -- -- ==== Constraints -- - The node must be a root. -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE modifyST #-} modifyST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> (a -> a) -> Int -> ST s P.Index modifyST seq root f k = do assertRootST seq root root' <- splayKthST seq root k modifyNodeST seq f root' pure root' -- | Amortized \(O(\log n)\). Exchanges the \(k\)-th node's monoid value. -- -- ==== Constraints -- - The node must be a root. -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE exchangeST #-} exchangeST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> a -> ST s (a, P.Index) exchangeST seq root k v = do assertRootST seq root root' <- splayKthST seq root k res <- exchangeNodeST seq root' v pure (res, root') -- | Amortized \(O(\log n)\). Returns the monoid product in an interval \([l, r)\). -- -- ==== Constraints -- - The node must be a root -- - \(0 \le l \le r \le n\) -- -- @since 1.2.0.0 {-# INLINEABLE prodST #-} prodST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> ST s (a, P.Index) prodST seq@Seq {sSeq} root l r = do s <- if P.nullIndex root then pure 0 else VGM.read sSeq (coerce root) let !_ = ACIA.checkInterval "AtCoder.Extra.Seq.Raw.prodST" l r s if l == r then pure (mempty, root) else unsafeProdST seq root l r -- | Amortized \(O(\log n)\). Returns the monoid product in an interval \([l, r)\). Returns -- `Nothing` if an invalid interval is given or for an empty sequence. -- -- @since 1.2.0.0 {-# INLINEABLE prodMaybeST #-} prodMaybeST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> ST s (Maybe (a, P.Index)) prodMaybeST seq@Seq {sSeq} root l r | P.nullIndex root = pure Nothing | otherwise = do s <- VGM.read sSeq (coerce root) if not (ACIA.testInterval l r s) then pure Nothing else if l == r then pure $ Just (mempty, root) else Just <$> unsafeProdST seq root l r -- | Amortized \(O(\log n)\). -- -- ==== Constraint -- - \(0 \le \lt r \le n\). Note that the interval must have positive length. {-# INLINEABLE unsafeProdST #-} unsafeProdST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> ST s (a, P.Index) unsafeProdST seq@Seq {..} root l r = do assertRootST seq root target <- sliceST seq root l r res <- VGM.read prodSeq $ coerce target splayST seq target True pure (res, target) -- | Amortized \(O(\log n)\). Returns the monoid product of the whole sequence. Returns `mempty` -- for an empty sequence. -- -- ==== Constraint -- - The node must be null or a root. -- -- @since 1.2.0.0 {-# INLINEABLE prodAllST #-} prodAllST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> ST s a prodAllST seq@Seq {..} root = do if P.nullIndex root then pure mempty else do assertRootST seq root VGM.read prodSeq $ coerce root -- | Amortized \(O(\log n)\). Given an interval \([l, r)\), applies a monoid action \(f\). -- -- ==== Constraints -- - \(0 \le l \le r \le n\) -- -- @since 1.2.0.0 {-# INLINEABLE applyInST #-} applyInST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> f -> ST s P.Index applyInST seq@Seq {..} root l r act = do -- assertRootOrNullST seq root s <- if P.nullIndex root then pure 0 else VGM.read sSeq (coerce root) let !_ = ACIA.checkInterval "AtCoder.Extra.Seq.applyInST" l r s if l == r then pure root else do root' <- sliceST seq root l r applyNodeST seq root' act splayST seq root' True pure root' -- | \(O(1)\) Applies a monoid action \(f\) to the root of a sequence. -- -- @since 1.2.0.0 {-# INLINEABLE applyToRootST #-} applyToRootST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> f -> ST s () applyToRootST seq@Seq {..} root act | P.nullIndex root = pure () | otherwise = do rootP <- VGM.read pSeq (coerce root) when (P.nullIndex rootP) $ do applyNodeST seq root act -- | Amortized \(O(\log n)\). Reverses the sequence in \([l, r)\). -- -- ==== Constraints -- - The monoid action \(f\) must be commutative. -- - The monoid value \(v\) must be commutative. -- -- @since 1.2.0.0 {-# INLINEABLE reverseST #-} reverseST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> Int -> ST s P.Index reverseST seq@Seq {sSeq} root0 l r | P.nullIndex root0 = pure P.undefIndex | otherwise = do s <- VGM.read sSeq (coerce root0) if not (ACIA.testInterval l r s) then pure root0 else if l == r then pure root0 else do root' <- sliceST seq root0 l r reverseNodeST seq root' splayST seq root' True pure root' -- | Amortized \(O(\log n)\). Inserts a new node at \(k\) with initial monoid value \(v\). This -- functions for an empty index. -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le k \le n\) -- -- @since 1.2.0.0 {-# INLINEABLE insertST #-} insertST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> a -> ST s P.Index insertST seq root k v = do if P.nullIndex root then do -- `insertST` is actually `insertOrNewNodeST`: it's specifically designed to work for an empty -- sequence. newNodeST seq v else do (!l, !r) <- splitST seq root k node <- newNodeST seq v merge3ST seq l node r -- | Amortized \(O(\log n)\). Frees the \(k\)-th node and returns the monoid value of it. -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE deleteST #-} deleteST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s (a, P.Index) deleteST seq@Seq {..} root i = do (!l, !m, !r) <- split3ST seq root i (i + 1) x <- VGM.read vSeq (coerce m) freeNodeST seq m root' <- mergeST seq l r pure (x, root') -- | Amortized \(O(\log n)\). Frees the \(k\)-th node. -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE deleteST_ #-} deleteST_ :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s P.Index deleteST_ seq root i = do (!l, !m, !r) <- split3ST seq root i (i + 1) freeNodeST seq m root' <- mergeST seq l r pure root' -- | Amortized \(O(\log n)\). Detaches the \(k\)-th node and returns the new root of the original -- sequence. -- -- ==== Constraints -- - The node must be null or a root. -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE detachST #-} detachST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s P.Index detachST seq root i = do (!l, !m, !r) <- split3ST seq root i (i + 1) freeNodeST seq m root' <- mergeST seq l r pure root' -- ------------------------------------------------------------------------------------------------- -- Balancing -- ------------------------------------------------------------------------------------------------- -- | Amortized \(O(\log n)\). Rotates a child node. -- -- ==== Constraints -- - \(0 \le i \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE rotateST #-} rotateST :: (HasCallStack) => Seq s v a -> P.Index -> ST s () rotateST Seq {..} !i = do p <- VGM.read pSeq $ coerce i pl <- VGM.read lSeq $ coerce p c <- if pl == i then do -- p i -- / \ -- i -> p -- \ / -- r r r <- VGM.exchange rSeq (coerce i) p VGM.write lSeq (coerce p) r pure r else do -- p i -- \ / -- i -> p -- / \ -- l l l <- VGM.exchange lSeq (coerce i) p VGM.write rSeq (coerce p) l pure l pp <- VGM.read pSeq $ coerce p unless (P.nullIndex pp) $ do -- pp pp -- / -> / -- p i VGM.modify lSeq (\ppl -> if ppl == p then i else ppl) $ coerce pp -- pp pp -- \ -> \ -- p i VGM.modify rSeq (\ppr -> if ppr == p then i else ppr) $ coerce pp -- set parents VGM.write pSeq (coerce i) pp VGM.write pSeq (coerce p) i unless (P.nullIndex c) $ do VGM.write pSeq (coerce c) p -- | Amortized \(O(\log n)\). Moves up a node to be a root. -- -- @since 1.2.0.0 {-# INLINEABLE splayST #-} splayST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Bool -> ST s () splayST seq@Seq {..} i doneParentProp = do -- we have no chance to call `splayST` with `doneParentProp == False` though if doneParentProp then propNodeST seq i else propNodeFromRootST seq i let inner = do p <- VGM.read pSeq $ coerce i unless (P.nullIndex p) $ do pp <- VGM.read pSeq $ coerce p if P.nullIndex pp then do rotateST seq i updateNodeST seq p pure () else do pl <- VGM.read lSeq $ coerce p pr <- VGM.read rSeq $ coerce p ppl <- VGM.read lSeq $ coerce pp ppr <- VGM.read rSeq $ coerce pp if pl == i && ppl == p || pr == i && ppr == p then do -- same direction twice rotateST seq p rotateST seq i else do rotateST seq i rotateST seq i updateNodeST seq pp updateNodeST seq p inner inner updateNodeST seq i -- | Amortized \(O(\log n)\). Finds \(k\)-th node and splays it. Returns the new root. -- -- ==== Constraints -- - \(0 \le k \lt n\) -- -- @since 1.2.0.0 {-# INLINEABLE splayKthST #-} splayKthST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> Int -> ST s P.Index splayKthST seq@Seq {..} root0 k0 = do size <- VGM.read sSeq $ coerce root0 let !_ = ACIA.checkIndex "AtCoder.Extra.Seq.Raw.splayKthST" k0 size let inner root k = do propNodeST seq root l <- VGM.read lSeq $ coerce root -- The number of left children = the node's index counting from the leftmost. sizeL <- if P.nullIndex l then pure 0 else VGM.read sSeq $ coerce l case compare k sizeL of EQ -> pure root LT -> inner l k GT -> do r <- VGM.read rSeq $ coerce root inner r (k - (sizeL + 1)) target <- inner root0 k0 splayST seq target True pure target -- ------------------------------------------------------------------------------------------------- -- Bisection methods -- ------------------------------------------------------------------------------------------------- -- | Amortized \(O(\log n)\). -- -- @since 1.2.0.0 {-# INLINE ilowerBoundST #-} ilowerBoundST :: (SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value (Int -> a -> Bool) -> -- | (r, root) ST s (Int, P.Index) ilowerBoundST seq root f = stToPrim $ do if P.nullIndex root then pure (0, P.undefIndex) else do (!r, !_, !root') <- imaxRightST seq root f pure (r, root') -- | Amortized \(O(\log n)\). -- -- @since 1.2.0.0 {-# INLINE ilowerBoundM #-} ilowerBoundM :: (PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq (PrimState m) f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value (Int -> a -> m Bool) -> -- | (r, root) m (Int, P.Index) ilowerBoundM seq root f = do if P.nullIndex root then pure (0, P.undefIndex) else do (!r, !_, !root') <- imaxRightM seq root f pure (r, root') -- | Amortized \(O(\log n)\). -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINE ilowerBoundProdST #-} ilowerBoundProdST :: (SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid product (Int -> a -> Bool) -> -- | (r, root) ST s (Int, P.Index) ilowerBoundProdST seq root f = do if P.nullIndex root then pure (0, P.undefIndex) else do (!r, !_, !root') <- imaxRightProdST seq root f pure (r, root') -- | Amortized \(O(\log n)\). -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINE ilowerBoundProdM #-} ilowerBoundProdM :: (PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq (PrimState m) f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid product (Int -> a -> m Bool) -> -- | (r, root) m (Int, P.Index) ilowerBoundProdM seq root f = do if P.nullIndex root then pure (0, P.undefIndex) else do (!r, !_, !root') <- imaxRightProdM seq root f pure (r, root') -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- @since 1.2.0.0 {-# INLINE isplitMaxRightST #-} isplitMaxRightST :: (SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value (Int -> a -> Bool) -> -- | (left, right) sequences where \(f\) holds for the left ST s (P.Index, P.Index) isplitMaxRightST seq root f = stToPrim $ isplitMaxRightM seq root (\i x -> pure (f i x)) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- @since 1.2.0.0 {-# INLINEABLE isplitMaxRightM #-} isplitMaxRightM :: (PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq (PrimState m) f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value (Int -> a -> m Bool) -> -- | (left, right) sequences where \(f\) holds for the left m (P.Index, P.Index) isplitMaxRightM seq@Seq {..} root f | P.nullIndex root = pure (P.undefIndex, P.undefIndex) | otherwise = do stToPrim $ assertRootST seq root (!_, !c, !_) <- imaxRightM seq root f if P.nullIndex c then stToPrim $ do -- `f` does hot hold splayST seq root True pure (P.undefIndex, root) else stToPrim $ do splayST seq c True right <- VGM.read rSeq (coerce c) if P.nullIndex right then do -- `f` holds for the whole sequence pure (c, P.undefIndex) else do -- `f` holds for part of the sequence. detach the right child VGM.write pSeq (coerce right) P.undefIndex VGM.write rSeq (coerce c) P.undefIndex updateNodeST seq c pure (c, right) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- @since 1.2.0.0 {-# INLINE isplitMaxRightProdST #-} isplitMaxRightProdST :: (SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid value (Int -> a -> Bool) -> -- | (left, right) sequences where \(f\) holds for the left ST s (P.Index, P.Index) isplitMaxRightProdST seq root f = stToPrim $ isplitMaxRightProdM seq root (\i x -> pure (f i x)) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- @since 1.2.0.0 {-# INLINEABLE isplitMaxRightProdM #-} isplitMaxRightProdM :: (PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq (PrimState m) f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value -- | \(r\) (Int -> a -> m Bool) -> -- | (left, right) sequences where \(f\) holds for the left m (P.Index, P.Index) isplitMaxRightProdM seq@Seq {..} root f | P.nullIndex root = pure (P.undefIndex, P.undefIndex) | otherwise = do stToPrim $ assertRootST seq root (!_, !c, !_) <- imaxRightProdM seq root f if P.nullIndex c then stToPrim $ do -- `f` does hot hold splayST seq root True pure (P.undefIndex, root) else stToPrim $ do splayST seq c True right <- VGM.read rSeq (coerce c) if P.nullIndex right then do -- `f` holds for the whole sequence pure (c, P.undefIndex) else do -- `f` holds for part of the sequence. detach the right child VGM.write pSeq (coerce right) P.undefIndex VGM.write rSeq (coerce c) P.undefIndex updateNodeST seq c pure (c, right) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v\) -- where \(f(v)\) holds for every \(v_i (0 \le i \lt k)\). Note that \(f\) works for a single -- node, not a monoid product. -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINE imaxRightST #-} imaxRightST :: (SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value (Int -> a -> Bool) -> -- | (r, left, right) ST s (Int, P.Index, P.Index) imaxRightST seq root0 f = stToPrim $ imaxRightM seq root0 (\i x -> pure (f i x)) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \(v_i (0 \le i \le k)\). Note that \(f\) works for a single -- node, not a monoid product. -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINEABLE imaxRightM #-} imaxRightM :: (PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq (PrimState m) f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_i)\) that takes the index and the monoid value (Int -> a -> m Bool) -> -- | (r, left, right) m (Int, P.Index, P.Index) imaxRightM seq@Seq {..} root0 f = do let inner offset parent root lastYes | P.nullIndex root = pure (offset, lastYes, parent) | otherwise = do stToPrim $ propNodeST seq root l <- stToPrim $ VGM.read lSeq (coerce root) v <- stToPrim $ VGM.read vSeq (coerce root) pos <- stToPrim $ do if P.nullIndex l then pure offset else (offset +) <$> VGM.read sSeq (coerce l) !b <- f pos v if b then do r <- stToPrim $ VGM.read rSeq $ coerce root inner (pos + 1) root r root else do inner offset root l lastYes (!r, !yes, !root') <- inner 0 P.undefIndex root0 P.undefIndex stToPrim $ splayST seq root' True pure (r, yes, root') -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINE imaxRightProdST #-} imaxRightProdST :: (SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid value (Int -> a -> Bool) -> -- | (ilowerBound, rightmost node, new root) ST s (Int, P.Index, P.Index) imaxRightProdST seq root0 f = imaxRightProdM seq root0 (\i x -> pure (f i x)) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.0.0 {-# INLINEABLE imaxRightProdM #-} imaxRightProdM :: (PrimMonad m, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq (PrimState m) f a -> -- | Root node P.Index -> -- | User predicate \(f(i, v_0 \dots v_i)\) that takes the index and the monoid value (Int -> a -> m Bool) -> -- | (ilowerBound, rightmost node, new root) m (Int, P.Index, P.Index) imaxRightProdM seq@Seq {..} root0 f = do let inner !acc offset parent root lastYes | P.nullIndex root = pure (offset, lastYes, parent) | otherwise = do stToPrim $ propNodeST seq root l <- stToPrim $ VGM.read lSeq $ coerce root pos <- stToPrim $ do if P.nullIndex l then pure offset else (offset +) <$> VGM.read sSeq (coerce l) -- [0, pos] prodM <- stToPrim $ do -- detach right child (temporarily) and read the product rootR <- VGM.exchange rSeq (coerce root) P.undefIndex updateNodeST seq root prodRoot <- VGM.read prodSeq (coerce root) -- attach the right child again VGM.write rSeq (coerce root) rootR updateNodeST seq root pure $! acc <> prodRoot !b <- f pos prodM if b then do r <- stToPrim $ VGM.read rSeq $ coerce root inner prodM (pos + 1) root r root else do inner acc offset root l lastYes (!r, !yes, !root') <- inner mempty 0 P.undefIndex root0 P.undefIndex stToPrim $ splayST seq root' True pure (r, yes, root') -- ------------------------------------------------------------------------------------------------- -- Conversions -- ------------------------------------------------------------------------------------------------- -- | Amortized \(O(n)\). Returns the sequence of monoid values. -- -- @since 1.2.0.0 {-# INLINEABLE freezeST #-} freezeST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> ST s (VU.Vector a) freezeST seq@Seq {sSeq, lSeq, rSeq, vSeq} root0 | P.nullIndex root0 = pure VU.empty | otherwise = do size <- VGM.read sSeq (coerce root0) res <- VUM.unsafeNew size let inner i root | P.nullIndex root = pure i | otherwise = do -- visit from left to right propNodeST seq root i' <- inner i =<< VGM.read lSeq (coerce root) vx <- VGM.read vSeq (coerce root) VGM.write res i' vx inner (i' + 1) =<< VGM.read rSeq (coerce root) _ <- inner 0 root0 VU.unsafeFreeze res -- ------------------------------------------------------------------------------------------------- -- Internals and node methods -- ------------------------------------------------------------------------------------------------- -- | Amortized \(O(\log n)\). -- -- @since 1.2.1.0 {-# INLINEABLE splitMaxRightWithST #-} splitMaxRightWithST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate \(f(i)\) (P.Index -> ST s Bool) -> -- | (left, right) sequences where \(f\) holds for the left ST s (P.Index, P.Index) splitMaxRightWithST seq@Seq {..} root f | P.nullIndex root = pure (P.undefIndex, P.undefIndex) | otherwise = do assertRootST seq root (!c, !_) <- maxRightWithST seq root f if P.nullIndex c then do -- `f` does hot hold splayST seq root True pure (P.undefIndex, root) else do splayST seq c True right <- VGM.read rSeq (coerce c) if P.nullIndex right then do -- `f` holds for the whole sequence pure (c, P.undefIndex) else do -- `f` holds for part of the sequence. detach the right child VGM.write pSeq (coerce right) P.undefIndex VGM.write rSeq (coerce c) P.undefIndex updateNodeST seq c pure (c, right) -- | Amortized \(O(\log n)\). Given a monotonious sequence, returns the rightmost node \(v_k\) -- where \(f(v)\) holds for every \([0, i) (0 \le i \lt k)\). -- -- ==== Constraints -- - The node must be a root. -- -- @since 1.2.1.0 {-# INLINEABLE maxRightWithST #-} maxRightWithST :: (HasCallStack, SegAct f a, Eq f, Monoid f, VU.Unbox f, Monoid a, VU.Unbox a) => -- | Sequence storage Seq s f a -> -- | Root node P.Index -> -- | User predicate (P.Index -> ST s Bool) -> -- | (rightmost node, new root) ST s (P.Index, P.Index) maxRightWithST seq@Seq {..} root0 f = do let inner parent lastYes root | P.nullIndex root = pure (lastYes, parent) | otherwise = do stToPrim $ propNodeST seq root !b <- f root if b then inner root root =<< VGM.read rSeq (coerce root) else inner root lastYes =<< VGM.read lSeq (coerce root) (!yes, !root') <- inner P.undefIndex P.undefIndex root0 stToPrim $ splayST seq root' True pure (yes, root') -- NOTE(pref): inlining node functions are important for the speed -- | \(O(1)\) Recomputes the node size and the monoid product. -- -- @since 1.2.1.0 {-# INLINEABLE updateNodeST #-} updateNodeST :: (Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> ST s () updateNodeST Seq {..} i = do l <- VGM.read lSeq (coerce i) r <- VGM.read rSeq (coerce i) prodM <- VGM.read vSeq (coerce i) (!size', !prod') <- if P.nullIndex l then pure (1, prodM) else do sizeL <- VGM.read sSeq (coerce l) prodL <- VGM.read prodSeq (coerce l) pure (sizeL + 1, prodL <> prodM) (!size'', !prod'') <- if P.nullIndex r then pure (size', prod') else do sizeR <- VGM.read sSeq (coerce r) prodR <- VGM.read prodSeq (coerce r) pure (size' + sizeR, prod' <> prodR) VGM.write sSeq (coerce i) size'' VGM.write prodSeq (coerce i) prod'' -- | \(O(1)\) Writes to the monoid value of a node. -- -- @since 1.2.1.0 {-# INLINE writeNodeST #-} writeNodeST :: (Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> a -> ST s () writeNodeST seq@Seq {..} root v = do assertRootST seq root VGM.write vSeq (coerce root) v updateNodeST seq root -- | \(O(1)\) Modifies the monoid value of a node. -- -- @since 1.2.1.0 {-# INLINE modifyNodeST #-} modifyNodeST :: (HasCallStack, Monoid a, VU.Unbox a) => Seq s f a -> (a -> a) -> P.Index -> ST s () modifyNodeST seq@Seq {..} f root = do assertRootST seq root VGM.modify vSeq f $ coerce root updateNodeST seq root -- | \(O(1)\) Exchanges the monoid value of a node. -- -- @since 1.2.1.0 {-# INLINE exchangeNodeST #-} exchangeNodeST :: (HasCallStack, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> a -> ST s a exchangeNodeST seq@Seq {..} root v = do assertRootST seq root res <- VGM.exchange vSeq (coerce root) v updateNodeST seq root pure res -- | \(O(1)\) Swaps the left and the right children. {-# INLINE swapLrNodeST #-} swapLrNodeST :: Seq s f a -> P.Index -> ST s () swapLrNodeST Seq {..} i = do VGM.modifyM lSeq (VGM.exchange rSeq (coerce i)) (coerce i) -- | \(O(1)\) Reverses the left and the right children, lazily and recursively. {-# INLINE reverseNodeST #-} reverseNodeST :: Seq s f a -> P.Index -> ST s () reverseNodeST seq@Seq {..} i = do swapLrNodeST seq i -- lazily propagate new reverse or cancel: VGM.modify revSeq (xor (Bit True)) $ coerce i -- | Amortized \(O(\log n)\). Propgates the lazily propagated values on a node. -- -- @since 1.2.1.0 {-# INLINE propNodeST #-} -- NOTE(pref): Although this function is large, inlining it needs for the speed. propNodeST :: (HasCallStack, SegAct f a, Eq f, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> ST s () propNodeST seq@Seq {..} i = do -- action act <- VGM.exchange lazySeq (coerce i) mempty -- this is where `Eq f` is required: when (act /= mempty) $ do l <- VGM.read lSeq $ coerce i unless (P.nullIndex l) $ do applyNodeST seq l act r <- VGM.read rSeq $ coerce i unless (P.nullIndex r) $ do applyNodeST seq r act -- reverse Bit b <- VGM.exchange revSeq (coerce i) (Bit False) when b $ do l <- VGM.read lSeq $ coerce i unless (P.nullIndex l) $ do -- propagate new reverse or cancel: reverseNodeST seq l r <- VGM.read rSeq $ coerce i unless (P.nullIndex r) $ do -- propagate new reverse or cancel: reverseNodeST seq r -- | Amortized \(O(\log n)\). Propagetes from the root to the given node. {-# INLINE propNodeFromRootST #-} propNodeFromRootST :: (HasCallStack, SegAct f a, VU.Unbox f, VU.Unbox a, Monoid a) => Seq s f a -> P.Index -> ST s () propNodeFromRootST Seq {..} = inner where inner i = do p <- VGM.read pSeq $ coerce i unless (P.nullIndex p) $ do inner p inner i -- | Amortized \(O(\log n)\). Propgates at a node. -- -- @since 1.2.1.0 {-# INLINE applyNodeST #-} applyNodeST :: (HasCallStack, SegAct f a, VU.Unbox f, Monoid a, VU.Unbox a) => Seq s f a -> P.Index -> f -> ST s () applyNodeST Seq {..} i act = do len <- VGM.read sSeq $ coerce i VGM.modify vSeq (segAct act) $ coerce i VGM.modify prodSeq (segActWithLength len act) $ coerce i VGM.modify lazySeq (act <>) $ coerce i