ac-library-hs 1.0.0.1 → 1.1.0.0
raw patch · 78 files changed
+9333/−709 lines, 78 filesdep +containersdep +unordered-containersPVP ok
version bump matches the API change (PVP)
Dependencies added: containers, unordered-containers
API changes (from Hackage documentation)
- AtCoder.Extra.Monoid: RangeAddId :: a -> RangeAddId a
- AtCoder.Extra.Monoid: RangeSetId :: RangeSetIdRepr a -> RangeSetId a
- AtCoder.Extra.Monoid: newtype RangeAddId a
- AtCoder.Extra.Monoid: newtype RangeSetId a
- AtCoder.Extra.Monoid.RangeAdd: instance GHC.Num.Num a => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeAdd.RangeAdd a) (Data.Semigroup.Internal.Sum a)
- AtCoder.Extra.Monoid.RangeAdd: instance GHC.Num.Num a => GHC.Base.Monoid (AtCoder.Extra.Monoid.RangeAdd.RangeAdd a)
- AtCoder.Extra.Monoid.RangeAdd: instance GHC.Num.Num a => GHC.Base.Semigroup (AtCoder.Extra.Monoid.RangeAdd.RangeAdd a)
- AtCoder.Extra.Monoid.RangeAddId: RangeAddId :: a -> RangeAddId a
- AtCoder.Extra.Monoid.RangeAddId: act :: Num a => RangeAddId a -> a -> a
- AtCoder.Extra.Monoid.RangeAddId: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Unboxed.Base.Unbox (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Classes.Eq a => GHC.Classes.Eq (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Classes.Ord a => GHC.Classes.Ord (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Num.Num a => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a) (Data.Semigroup.Max a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Num.Num a => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a) (Data.Semigroup.Min a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Num.Num a => GHC.Base.Monoid (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Num.Num a => GHC.Base.Semigroup (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: instance GHC.Show.Show a => GHC.Show.Show (AtCoder.Extra.Monoid.RangeAddId.RangeAddId a)
- AtCoder.Extra.Monoid.RangeAddId: new :: a -> RangeAddId a
- AtCoder.Extra.Monoid.RangeAddId: newtype RangeAddId a
- AtCoder.Extra.Monoid.RangeSetId: RangeSetId :: RangeSetIdRepr a -> RangeSetId a
- AtCoder.Extra.Monoid.RangeSetId: act :: RangeSetId a -> a -> a
- AtCoder.Extra.Monoid.RangeSetId: instance (GHC.Classes.Ord a, GHC.Enum.Bounded a) => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeSetId.RangeSetId (Data.Semigroup.Max a)) (Data.Semigroup.Max a)
- AtCoder.Extra.Monoid.RangeSetId: instance (GHC.Classes.Ord a, GHC.Enum.Bounded a) => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeSetId.RangeSetId (Data.Semigroup.Min a)) (Data.Semigroup.Min a)
- AtCoder.Extra.Monoid.RangeSetId: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Unboxed.Base.Unbox (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance GHC.Base.Monoid a => GHC.Base.Monoid (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance GHC.Base.Semigroup (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance GHC.Classes.Eq a => GHC.Classes.Eq (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance GHC.Classes.Ord a => GHC.Classes.Ord (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: instance GHC.Show.Show a => GHC.Show.Show (AtCoder.Extra.Monoid.RangeSetId.RangeSetId a)
- AtCoder.Extra.Monoid.RangeSetId: new :: a -> RangeSetId a
- AtCoder.Extra.Monoid.RangeSetId: newtype RangeSetId a
+ AtCoder.Extra.Bisect: bisectL :: HasCallStack => Int -> Int -> (Int -> Bool) -> Maybe Int
+ AtCoder.Extra.Bisect: bisectLM :: (HasCallStack, Monad m) => Int -> Int -> (Int -> m Bool) -> m (Maybe Int)
+ AtCoder.Extra.Bisect: bisectR :: HasCallStack => Int -> Int -> (Int -> Bool) -> Maybe Int
+ AtCoder.Extra.Bisect: bisectRM :: (HasCallStack, Monad m) => Int -> Int -> (Int -> m Bool) -> m (Maybe Int)
+ AtCoder.Extra.Bisect: lowerBound :: (HasCallStack, Vector v a, Ord a) => v a -> a -> Maybe Int
+ AtCoder.Extra.Bisect: lowerBoundIn :: (Vector v a, Ord a) => Int -> Int -> v a -> a -> Maybe Int
+ AtCoder.Extra.Bisect: upperBound :: (HasCallStack, Vector v a, Ord a) => v a -> a -> Maybe Int
+ AtCoder.Extra.Bisect: upperBoundIn :: (Vector v a, Ord a) => Int -> Int -> v a -> a -> Maybe Int
+ AtCoder.Extra.Graph: scc :: Csr w -> Vector (Vector Int)
+ AtCoder.Extra.Graph: swapDupe :: Unbox (Int, Int, w) => Vector (Int, Int, w) -> Vector (Int, Int, w)
+ AtCoder.Extra.Graph: swapDupe' :: Unbox (Int, Int) => Vector (Int, Int) -> Vector (Int, Int)
+ AtCoder.Extra.Graph: topSort :: Int -> (Int -> Vector Int) -> Vector Int
+ AtCoder.Extra.HashMap: assocs :: (PrimMonad m, Unbox a) => HashMap (PrimState m) a -> m (Vector (Int, a))
+ AtCoder.Extra.HashMap: build :: (PrimMonad m, Unbox a) => Int -> Vector (Int, a) -> m (HashMap (PrimState m) a)
+ AtCoder.Extra.HashMap: capacity :: HashMap s a -> Int
+ AtCoder.Extra.HashMap: clear :: PrimMonad m => HashMap (PrimState m) a -> m ()
+ AtCoder.Extra.HashMap: data HashMap s a
+ AtCoder.Extra.HashMap: elems :: (PrimMonad m, Unbox a) => HashMap (PrimState m) a -> m (Vector a)
+ AtCoder.Extra.HashMap: exchange :: (HasCallStack, PrimMonad m, Unbox a) => HashMap (PrimState m) a -> Int -> a -> m (Maybe a)
+ AtCoder.Extra.HashMap: insert :: (HasCallStack, PrimMonad m, Unbox a) => HashMap (PrimState m) a -> Int -> a -> m ()
+ AtCoder.Extra.HashMap: insertWith :: (HasCallStack, PrimMonad m, Unbox a) => HashMap (PrimState m) a -> (a -> a -> a) -> Int -> a -> m ()
+ AtCoder.Extra.HashMap: keys :: (PrimMonad m, Unbox a) => HashMap (PrimState m) a -> m (Vector Int)
+ AtCoder.Extra.HashMap: lookup :: (HasCallStack, Unbox a, PrimMonad m) => HashMap (PrimState m) a -> Int -> m (Maybe a)
+ AtCoder.Extra.HashMap: member :: (HasCallStack, PrimMonad m) => HashMap (PrimState m) a -> Int -> m Bool
+ AtCoder.Extra.HashMap: modify :: (HasCallStack, PrimMonad m, Unbox a) => HashMap (PrimState m) a -> (a -> a) -> Int -> m ()
+ AtCoder.Extra.HashMap: modifyM :: (HasCallStack, PrimMonad m, Unbox a) => HashMap (PrimState m) a -> (a -> m a) -> Int -> m ()
+ AtCoder.Extra.HashMap: new :: (PrimMonad m, Unbox a) => Int -> m (HashMap (PrimState m) a)
+ AtCoder.Extra.HashMap: notMember :: (HasCallStack, PrimMonad m) => HashMap (PrimState m) a -> Int -> m Bool
+ AtCoder.Extra.HashMap: size :: PrimMonad m => HashMap (PrimState m) a -> m Int
+ AtCoder.Extra.HashMap: unsafeAssocs :: (PrimMonad m, Unbox a) => HashMap (PrimState m) a -> m (Vector (Int, a))
+ AtCoder.Extra.HashMap: unsafeElems :: (PrimMonad m, Unbox a) => HashMap (PrimState m) a -> m (Vector a)
+ AtCoder.Extra.HashMap: unsafeKeys :: (PrimMonad m, Unbox a) => HashMap (PrimState m) a -> m (Vector Int)
+ AtCoder.Extra.IntMap: assocs :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> m (Vector (Int, a))
+ AtCoder.Extra.IntMap: build :: (PrimMonad m, Unbox a) => Int -> Vector (Int, a) -> m (IntMap (PrimState m) a)
+ AtCoder.Extra.IntMap: capacity :: IntMap s a -> Int
+ AtCoder.Extra.IntMap: data IntMap s a
+ AtCoder.Extra.IntMap: delete :: PrimMonad m => IntMap (PrimState m) a -> Int -> m Bool
+ AtCoder.Extra.IntMap: deleteMax :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: deleteMin :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: delete_ :: PrimMonad m => IntMap (PrimState m) a -> Int -> m ()
+ AtCoder.Extra.IntMap: elems :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> m (Vector a)
+ AtCoder.Extra.IntMap: insert :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> Int -> a -> m ()
+ AtCoder.Extra.IntMap: insertWith :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> (a -> a -> a) -> Int -> a -> m ()
+ AtCoder.Extra.IntMap: keys :: PrimMonad m => IntMap (PrimState m) a -> m (Vector Int)
+ AtCoder.Extra.IntMap: lookup :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe a)
+ AtCoder.Extra.IntMap: lookupGE :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: lookupGT :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: lookupLE :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: lookupLT :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: lookupMax :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: lookupMin :: (PrimMonad m, Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))
+ AtCoder.Extra.IntMap: member :: PrimMonad m => IntMap (PrimState m) a -> Int -> m Bool
+ AtCoder.Extra.IntMap: modify :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> (a -> a) -> Int -> m ()
+ AtCoder.Extra.IntMap: modifyM :: (HasCallStack, PrimMonad m, Unbox a) => IntMap (PrimState m) a -> (a -> m a) -> Int -> m ()
+ AtCoder.Extra.IntMap: new :: (PrimMonad m, Unbox a) => Int -> m (IntMap (PrimState m) a)
+ AtCoder.Extra.IntMap: notMember :: PrimMonad m => IntMap (PrimState m) a -> Int -> m Bool
+ AtCoder.Extra.IntMap: null :: PrimMonad m => IntMap (PrimState m) a -> m Bool
+ AtCoder.Extra.IntMap: size :: PrimMonad m => IntMap (PrimState m) a -> m Int
+ AtCoder.Extra.IntSet: build :: PrimMonad m => Int -> Vector Int -> m (IntSet (PrimState m))
+ AtCoder.Extra.IntSet: capacity :: IntSet s -> Int
+ AtCoder.Extra.IntSet: data IntSet s
+ AtCoder.Extra.IntSet: delete :: PrimMonad m => IntSet (PrimState m) -> Int -> m Bool
+ AtCoder.Extra.IntSet: deleteMax :: PrimMonad m => IntSet (PrimState m) -> m (Maybe Int)
+ AtCoder.Extra.IntSet: deleteMin :: PrimMonad m => IntSet (PrimState m) -> m (Maybe Int)
+ AtCoder.Extra.IntSet: delete_ :: PrimMonad m => IntSet (PrimState m) -> Int -> m ()
+ AtCoder.Extra.IntSet: insert :: (HasCallStack, PrimMonad m) => IntSet (PrimState m) -> Int -> m ()
+ AtCoder.Extra.IntSet: keys :: PrimMonad m => IntSet (PrimState m) -> m (Vector Int)
+ AtCoder.Extra.IntSet: lookupGE :: PrimMonad m => IntSet (PrimState m) -> Int -> m (Maybe Int)
+ AtCoder.Extra.IntSet: lookupGT :: PrimMonad m => IntSet (PrimState m) -> Int -> m (Maybe Int)
+ AtCoder.Extra.IntSet: lookupLE :: PrimMonad m => IntSet (PrimState m) -> Int -> m (Maybe Int)
+ AtCoder.Extra.IntSet: lookupLT :: PrimMonad m => IntSet (PrimState m) -> Int -> m (Maybe Int)
+ AtCoder.Extra.IntSet: lookupMax :: PrimMonad m => IntSet (PrimState m) -> m (Maybe Int)
+ AtCoder.Extra.IntSet: lookupMin :: PrimMonad m => IntSet (PrimState m) -> m (Maybe Int)
+ AtCoder.Extra.IntSet: member :: PrimMonad m => IntSet (PrimState m) -> Int -> m Bool
+ AtCoder.Extra.IntSet: new :: PrimMonad m => Int -> m (IntSet (PrimState m))
+ AtCoder.Extra.IntSet: notMember :: PrimMonad m => IntSet (PrimState m) -> Int -> m Bool
+ AtCoder.Extra.IntSet: null :: PrimMonad m => IntSet (PrimState m) -> m Bool
+ AtCoder.Extra.IntSet: size :: PrimMonad m => IntSet (PrimState m) -> m Int
+ AtCoder.Extra.IntervalMap: build :: (PrimMonad m, Eq a, Unbox a) => Vector a -> m (IntervalMap (PrimState m) a)
+ AtCoder.Extra.IntervalMap: buildM :: (PrimMonad m, Eq a, Unbox a) => Vector a -> (Int -> Int -> a -> m ()) -> m (IntervalMap (PrimState m) a)
+ AtCoder.Extra.IntervalMap: capacity :: IntervalMap s a -> Int
+ AtCoder.Extra.IntervalMap: contains :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> m Bool
+ AtCoder.Extra.IntervalMap: data IntervalMap s a
+ AtCoder.Extra.IntervalMap: delete :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m ()
+ AtCoder.Extra.IntervalMap: deleteM :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> (Int -> Int -> a -> m ()) -> (Int -> Int -> a -> m ()) -> m ()
+ AtCoder.Extra.IntervalMap: freeze :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> m (Vector (Int, (Int, a)))
+ AtCoder.Extra.IntervalMap: insert :: (PrimMonad m, Eq a, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> a -> m ()
+ AtCoder.Extra.IntervalMap: insertM :: (PrimMonad m, Eq a, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> a -> (Int -> Int -> a -> m ()) -> (Int -> Int -> a -> m ()) -> m ()
+ AtCoder.Extra.IntervalMap: intersects :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m Bool
+ AtCoder.Extra.IntervalMap: lookup :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m (Maybe (Int, Int, a))
+ AtCoder.Extra.IntervalMap: new :: (PrimMonad m, Unbox a) => Int -> m (IntervalMap (PrimState m) a)
+ AtCoder.Extra.IntervalMap: overwrite :: (PrimMonad m, Eq a, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> a -> m ()
+ AtCoder.Extra.IntervalMap: overwriteM :: (PrimMonad m, Eq a, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> a -> (Int -> Int -> a -> m ()) -> (Int -> Int -> a -> m ()) -> m ()
+ AtCoder.Extra.IntervalMap: read :: (HasCallStack, PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m a
+ AtCoder.Extra.IntervalMap: readMaybe :: (PrimMonad m, Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m (Maybe a)
+ AtCoder.Extra.Math: invGcd :: Int -> Int -> (Int, Int)
+ AtCoder.Extra.Math: isPrime32 :: Int -> Bool
+ AtCoder.Extra.Math: primitiveRoot :: Int -> Int
+ AtCoder.Extra.Monoid: Mat2x2 :: Mat2x2Repr a -> Mat2x2 a
+ AtCoder.Extra.Monoid: V2 :: V2Repr a -> V2 a
+ AtCoder.Extra.Monoid: data RollingHash b p
+ AtCoder.Extra.Monoid: newtype Mat2x2 a
+ AtCoder.Extra.Monoid: newtype V2 a
+ AtCoder.Extra.Monoid: type Mat2x2Repr a = (a, a, a, a)
+ AtCoder.Extra.Monoid: type RangeSetRepr a = (Bit, a)
+ AtCoder.Extra.Monoid: type V2Repr a = (a, a)
+ AtCoder.Extra.Monoid.Affine1: ident :: Num a => Affine1 a
+ AtCoder.Extra.Monoid.Affine1: unAffine1 :: Affine1 a -> Affine1Repr a
+ AtCoder.Extra.Monoid.Affine1: zero :: Num a => Affine1 a
+ AtCoder.Extra.Monoid.Mat2x2: Mat2x2 :: Mat2x2Repr a -> Mat2x2 a
+ AtCoder.Extra.Monoid.Mat2x2: act :: Num a => Mat2x2 a -> V2 a -> V2 a
+ AtCoder.Extra.Monoid.Mat2x2: det :: Fractional e => Mat2x2 e -> e
+ AtCoder.Extra.Monoid.Mat2x2: ident :: Num a => Mat2x2 a
+ AtCoder.Extra.Monoid.Mat2x2: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Unboxed.Base.Unbox (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Classes.Eq a => GHC.Classes.Eq (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Classes.Ord a => GHC.Classes.Ord (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Num.Num a => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a) (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Num.Num a => AtCoder.LazySegTree.SegAct (Data.Semigroup.Internal.Dual (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)) (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Num.Num a => GHC.Base.Monoid (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Num.Num a => GHC.Base.Semigroup (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: instance GHC.Show.Show a => GHC.Show.Show (AtCoder.Extra.Monoid.Mat2x2.Mat2x2 a)
+ AtCoder.Extra.Monoid.Mat2x2: inv :: (HasCallStack, Fractional e, Eq e) => Mat2x2 e -> Mat2x2 e
+ AtCoder.Extra.Monoid.Mat2x2: map :: (a -> b) -> Mat2x2 a -> Mat2x2 b
+ AtCoder.Extra.Monoid.Mat2x2: new :: Num a => a -> a -> Mat2x2 a
+ AtCoder.Extra.Monoid.Mat2x2: newtype Mat2x2 a
+ AtCoder.Extra.Monoid.Mat2x2: type Mat2x2Repr a = (a, a, a, a)
+ AtCoder.Extra.Monoid.Mat2x2: unMat2x2 :: Mat2x2 a -> Mat2x2Repr a
+ AtCoder.Extra.Monoid.Mat2x2: zero :: Num a => Mat2x2 a
+ AtCoder.Extra.Monoid.RangeAdd: instance GHC.Base.Monoid (Data.Semigroup.Internal.Sum a) => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeAdd.RangeAdd (Data.Semigroup.Internal.Sum a)) (Data.Semigroup.Internal.Sum a)
+ AtCoder.Extra.Monoid.RangeAdd: instance GHC.Base.Monoid (Data.Semigroup.Max a) => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeAdd.RangeAdd (Data.Semigroup.Max a)) (Data.Semigroup.Max a)
+ AtCoder.Extra.Monoid.RangeAdd: instance GHC.Base.Monoid (Data.Semigroup.Min a) => AtCoder.LazySegTree.SegAct (AtCoder.Extra.Monoid.RangeAdd.RangeAdd (Data.Semigroup.Min a)) (Data.Semigroup.Min a)
+ AtCoder.Extra.Monoid.RangeAdd: instance GHC.Base.Monoid a => GHC.Base.Monoid (AtCoder.Extra.Monoid.RangeAdd.RangeAdd a)
+ AtCoder.Extra.Monoid.RangeAdd: instance GHC.Base.Semigroup a => GHC.Base.Semigroup (AtCoder.Extra.Monoid.RangeAdd.RangeAdd a)
+ AtCoder.Extra.Monoid.RangeAdd: unRangeAdd :: RangeAdd a -> a
+ AtCoder.Extra.Monoid.RangeSet: type RangeSetRepr a = (Bit, a)
+ AtCoder.Extra.Monoid.RangeSet: unRangeSet :: RangeSet a -> RangeSetRepr a
+ AtCoder.Extra.Monoid.RollingHash: RollingHash :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> RollingHash b p
+ AtCoder.Extra.Monoid.RollingHash: [hashRH] :: RollingHash b p -> {-# UNPACK #-} !Int
+ AtCoder.Extra.Monoid.RollingHash: [nextDigitRH] :: RollingHash b p -> {-# UNPACK #-} !Int
+ AtCoder.Extra.Monoid.RollingHash: data RollingHash b p
+ AtCoder.Extra.Monoid.RollingHash: instance (GHC.TypeNats.KnownNat b, GHC.TypeNats.KnownNat p) => GHC.Base.Monoid (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: instance (GHC.TypeNats.KnownNat b, GHC.TypeNats.KnownNat p) => GHC.Base.Semigroup (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: instance forall k1 (b :: k1) k2 (p :: k2). Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: instance forall k1 (b :: k1) k2 (p :: k2). Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: instance forall k1 (b :: k1) k2 (p :: k2). GHC.Classes.Eq (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: instance forall k1 (b :: k1) k2 (p :: k2). GHC.Show.Show (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: instance forall k1 k2 (b :: k1) (p :: k2). Data.Vector.Unboxed.Base.IsoUnbox (AtCoder.Extra.Monoid.RollingHash.RollingHash b p) AtCoder.Extra.Monoid.RollingHash.RHRepr
+ AtCoder.Extra.Monoid.RollingHash: instance forall k1 k2 (b :: k1) (p :: k2). Data.Vector.Unboxed.Base.Unbox (AtCoder.Extra.Monoid.RollingHash.RollingHash b p)
+ AtCoder.Extra.Monoid.RollingHash: new :: forall b p. (KnownNat b, KnownNat p) => Int -> RollingHash b p
+ AtCoder.Extra.Monoid.RollingHash: unsafeNew :: forall b p. (KnownNat b, KnownNat p) => Int -> RollingHash b p
+ AtCoder.Extra.Monoid.V2: V2 :: V2Repr a -> V2 a
+ AtCoder.Extra.Monoid.V2: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Base.Vector Data.Vector.Unboxed.Base.Vector (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Generic.Mutable.Base.MVector Data.Vector.Unboxed.Base.MVector (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance Data.Vector.Unboxed.Base.Unbox a => Data.Vector.Unboxed.Base.Unbox (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance GHC.Classes.Eq a => GHC.Classes.Eq (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance GHC.Classes.Ord a => GHC.Classes.Ord (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance GHC.Num.Num a => GHC.Base.Monoid (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance GHC.Num.Num a => GHC.Base.Semigroup (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: instance GHC.Show.Show a => GHC.Show.Show (AtCoder.Extra.Monoid.V2.V2 a)
+ AtCoder.Extra.Monoid.V2: new :: Num a => a -> V2 a
+ AtCoder.Extra.Monoid.V2: newtype V2 a
+ AtCoder.Extra.Monoid.V2: type V2Repr a = (a, a)
+ AtCoder.Extra.Monoid.V2: unV2 :: V2 a -> a
+ AtCoder.Extra.MultiSet: add :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> Int -> m ()
+ AtCoder.Extra.MultiSet: assocs :: PrimMonad m => MultiSet (PrimState m) -> m (Vector (Int, Int))
+ AtCoder.Extra.MultiSet: capacity :: MultiSet s -> Int
+ AtCoder.Extra.MultiSet: data MultiSet s
+ AtCoder.Extra.MultiSet: dec :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> m ()
+ AtCoder.Extra.MultiSet: delete :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> m ()
+ AtCoder.Extra.MultiSet: elems :: PrimMonad m => MultiSet (PrimState m) -> m (Vector Int)
+ AtCoder.Extra.MultiSet: inc :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> m ()
+ AtCoder.Extra.MultiSet: insert :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> Int -> m ()
+ AtCoder.Extra.MultiSet: keys :: PrimMonad m => MultiSet (PrimState m) -> m (Vector Int)
+ AtCoder.Extra.MultiSet: lookup :: PrimMonad m => MultiSet (PrimState m) -> Int -> m (Maybe Int)
+ AtCoder.Extra.MultiSet: member :: PrimMonad m => MultiSet (PrimState m) -> Int -> m Bool
+ AtCoder.Extra.MultiSet: new :: PrimMonad m => Int -> m (MultiSet (PrimState m))
+ AtCoder.Extra.MultiSet: notMember :: PrimMonad m => MultiSet (PrimState m) -> Int -> m Bool
+ AtCoder.Extra.MultiSet: size :: PrimMonad m => MultiSet (PrimState m) -> m Int
+ AtCoder.Extra.MultiSet: sub :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> Int -> m ()
+ AtCoder.Extra.MultiSet: unsafeAssocs :: PrimMonad m => MultiSet (PrimState m) -> m (Vector (Int, Int))
+ AtCoder.Extra.MultiSet: unsafeElems :: PrimMonad m => MultiSet (PrimState m) -> m (Vector Int)
+ AtCoder.Extra.MultiSet: unsafeKeys :: PrimMonad m => MultiSet (PrimState m) -> m (Vector Int)
+ AtCoder.Extra.Pdsu: canMerge :: (HasCallStack, PrimMonad m, Semigroup a, Eq a, Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> a -> m Bool
+ AtCoder.Extra.Pdsu: clear :: forall m a. (PrimMonad m, Monoid a, Unbox a) => Pdsu (PrimState m) a -> m ()
+ AtCoder.Extra.Pdsu: data Pdsu s a
+ AtCoder.Extra.Pdsu: diff :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> m (Maybe a)
+ AtCoder.Extra.Pdsu: groups :: (PrimMonad m, Semigroup a, Unbox a) => Pdsu (PrimState m) a -> m (Vector (Vector Int))
+ AtCoder.Extra.Pdsu: leader :: (HasCallStack, PrimMonad m, Semigroup a, Unbox a) => Pdsu (PrimState m) a -> Int -> m Int
+ AtCoder.Extra.Pdsu: merge :: (HasCallStack, PrimMonad m, Monoid a, Ord a, Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> a -> m Bool
+ AtCoder.Extra.Pdsu: merge_ :: (HasCallStack, PrimMonad m, Monoid a, Ord a, Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> a -> m ()
+ AtCoder.Extra.Pdsu: new :: forall m a. (PrimMonad m, Monoid a, Unbox a) => Int -> (a -> a) -> m (Pdsu (PrimState m) a)
+ AtCoder.Extra.Pdsu: pot :: (HasCallStack, PrimMonad m, Semigroup a, Unbox a) => Pdsu (PrimState m) a -> Int -> m a
+ AtCoder.Extra.Pdsu: same :: (HasCallStack, PrimMonad m, Semigroup a, Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> m Bool
+ AtCoder.Extra.Pdsu: size :: (HasCallStack, PrimMonad m, Semigroup a, Unbox a) => Pdsu (PrimState m) a -> Int -> m Int
+ AtCoder.Extra.Pdsu: unsafeDiff :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> m a
+ AtCoder.Extra.Semigroup.Matrix: Matrix :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !Vector a -> Matrix a
+ AtCoder.Extra.Semigroup.Matrix: [hM] :: Matrix a -> {-# UNPACK #-} !Int
+ AtCoder.Extra.Semigroup.Matrix: [vecM] :: Matrix a -> !Vector a
+ AtCoder.Extra.Semigroup.Matrix: [wM] :: Matrix a -> {-# UNPACK #-} !Int
+ AtCoder.Extra.Semigroup.Matrix: data Matrix a
+ AtCoder.Extra.Semigroup.Matrix: diag :: (Unbox a, Num a) => Int -> Vector a -> Matrix a
+ AtCoder.Extra.Semigroup.Matrix: ident :: (Unbox a, Num a) => Int -> Matrix a
+ AtCoder.Extra.Semigroup.Matrix: instance (Data.Vector.Unboxed.Base.Unbox a, GHC.Classes.Eq a) => GHC.Classes.Eq (AtCoder.Extra.Semigroup.Matrix.Matrix a)
+ AtCoder.Extra.Semigroup.Matrix: instance (GHC.Num.Num a, Data.Vector.Unboxed.Base.Unbox a) => GHC.Base.Semigroup (AtCoder.Extra.Semigroup.Matrix.Matrix a)
+ AtCoder.Extra.Semigroup.Matrix: instance (GHC.Show.Show a, Data.Vector.Unboxed.Base.Unbox a) => GHC.Show.Show (AtCoder.Extra.Semigroup.Matrix.Matrix a)
+ AtCoder.Extra.Semigroup.Matrix: map :: (Unbox a, Unbox b) => (a -> b) -> Matrix a -> Matrix b
+ AtCoder.Extra.Semigroup.Matrix: mul :: (Num e, Unbox e) => Matrix e -> Matrix e -> Matrix e
+ AtCoder.Extra.Semigroup.Matrix: mulMint :: forall a. KnownNat a => Matrix (ModInt a) -> Matrix (ModInt a) -> Matrix (ModInt a)
+ AtCoder.Extra.Semigroup.Matrix: mulMod :: Int -> Matrix Int -> Matrix Int -> Matrix Int
+ AtCoder.Extra.Semigroup.Matrix: mulToCol :: (Num a, Unbox a) => Matrix a -> Col a -> Col a
+ AtCoder.Extra.Semigroup.Matrix: new :: (HasCallStack, Unbox a) => Int -> Int -> Vector a -> Matrix a
+ AtCoder.Extra.Semigroup.Matrix: pow :: Int -> Matrix Int -> Matrix Int
+ AtCoder.Extra.Semigroup.Matrix: powMint :: forall m. KnownNat m => Int -> Matrix (ModInt m) -> Matrix (ModInt m)
+ AtCoder.Extra.Semigroup.Matrix: powMod :: Int -> Int -> Matrix Int -> Matrix Int
+ AtCoder.Extra.Semigroup.Matrix: zero :: (Unbox a, Num a) => Int -> Matrix a
+ AtCoder.Extra.Semigroup.Permutation: Permutation :: Vector Int -> Permutation
+ AtCoder.Extra.Semigroup.Permutation: [unPermutation] :: Permutation -> Vector Int
+ AtCoder.Extra.Semigroup.Permutation: act :: HasCallStack => Permutation -> Int -> Int
+ AtCoder.Extra.Semigroup.Permutation: ident :: Int -> Permutation
+ AtCoder.Extra.Semigroup.Permutation: instance GHC.Base.Semigroup AtCoder.Extra.Semigroup.Permutation.Permutation
+ AtCoder.Extra.Semigroup.Permutation: instance GHC.Classes.Eq AtCoder.Extra.Semigroup.Permutation.Permutation
+ AtCoder.Extra.Semigroup.Permutation: instance GHC.Show.Show AtCoder.Extra.Semigroup.Permutation.Permutation
+ AtCoder.Extra.Semigroup.Permutation: length :: HasCallStack => Permutation -> Int
+ AtCoder.Extra.Semigroup.Permutation: new :: HasCallStack => Vector Int -> Permutation
+ AtCoder.Extra.Semigroup.Permutation: newtype Permutation
+ AtCoder.Extra.Semigroup.Permutation: unsafeNew :: HasCallStack => Vector Int -> Permutation
+ AtCoder.Extra.Semigroup.Permutation: zero :: Int -> Permutation
+ AtCoder.Extra.Tree: fold :: (HasCallStack, Unbox w) => (Int -> Vector (Int, w)) -> (Int -> a) -> (a -> (Int, w) -> f) -> (f -> a -> a) -> Int -> a
+ AtCoder.Extra.Tree: foldReroot :: forall w f a. (HasCallStack, Unbox w, Unbox a, Unbox f, Monoid f) => Int -> (Int -> Vector (Int, w)) -> (Int -> a) -> (a -> (Int, w) -> f) -> (f -> a -> a) -> Vector a
+ AtCoder.Extra.Tree: scan :: (Unbox w, Vector v a) => Int -> (Int -> Vector (Int, w)) -> (Int -> a) -> (a -> (Int, w) -> f) -> (f -> a -> a) -> Int -> v a
+ AtCoder.Extra.Tree.Hld: Hld :: {-# UNPACK #-} !Vertex -> !Vector Vertex -> !Vector VertexHld -> !Vector Vertex -> !Vector Vertex -> !Vector Int -> !Vector Int -> Hld
+ AtCoder.Extra.Tree.Hld: WeightsAreOnEdges :: WeightPolicy
+ AtCoder.Extra.Tree.Hld: WeightsAreOnVertices :: WeightPolicy
+ AtCoder.Extra.Tree.Hld: [depthHld] :: Hld -> !Vector Int
+ AtCoder.Extra.Tree.Hld: [headHld] :: Hld -> !Vector Vertex
+ AtCoder.Extra.Tree.Hld: [indexHld] :: Hld -> !Vector VertexHld
+ AtCoder.Extra.Tree.Hld: [parentHld] :: Hld -> !Vector Vertex
+ AtCoder.Extra.Tree.Hld: [revIndexHld] :: Hld -> !Vector Vertex
+ AtCoder.Extra.Tree.Hld: [rootHld] :: Hld -> {-# UNPACK #-} !Vertex
+ AtCoder.Extra.Tree.Hld: [subtreeSizeHld] :: Hld -> !Vector Int
+ AtCoder.Extra.Tree.Hld: ancestor :: HasCallStack => Hld -> Vertex -> Int -> Vertex
+ AtCoder.Extra.Tree.Hld: data Hld
+ AtCoder.Extra.Tree.Hld: data WeightPolicy
+ AtCoder.Extra.Tree.Hld: instance GHC.Classes.Eq AtCoder.Extra.Tree.Hld.Hld
+ AtCoder.Extra.Tree.Hld: instance GHC.Classes.Eq AtCoder.Extra.Tree.Hld.WeightPolicy
+ AtCoder.Extra.Tree.Hld: instance GHC.Show.Show AtCoder.Extra.Tree.Hld.Hld
+ AtCoder.Extra.Tree.Hld: instance GHC.Show.Show AtCoder.Extra.Tree.Hld.WeightPolicy
+ AtCoder.Extra.Tree.Hld: isInSubtree :: HasCallStack => Hld -> Vertex -> Vertex -> Bool
+ AtCoder.Extra.Tree.Hld: jump :: HasCallStack => Hld -> Vertex -> Vertex -> Int -> Maybe Vertex
+ AtCoder.Extra.Tree.Hld: lca :: HasCallStack => Hld -> Vertex -> Vertex -> Vertex
+ AtCoder.Extra.Tree.Hld: lengthBetween :: HasCallStack => Hld -> Vertex -> Vertex -> Int
+ AtCoder.Extra.Tree.Hld: new :: forall w. HasCallStack => Csr w -> Hld
+ AtCoder.Extra.Tree.Hld: newAt :: forall w. HasCallStack => Csr w -> Vertex -> Hld
+ AtCoder.Extra.Tree.Hld: path :: HasCallStack => Hld -> Vertex -> Vertex -> [Vertex]
+ AtCoder.Extra.Tree.Hld: pathSegmentsInclusive :: HasCallStack => WeightPolicy -> Hld -> Vertex -> Vertex -> [(VertexHld, VertexHld)]
+ AtCoder.Extra.Tree.Hld: prod :: (HasCallStack, Monoid mono, Monad m) => WeightPolicy -> Hld -> (VertexHld -> VertexHld -> m mono) -> (VertexHld -> VertexHld -> m mono) -> Vertex -> Vertex -> m mono
+ AtCoder.Extra.Tree.Hld: subtreeSegmentInclusive :: HasCallStack => Hld -> Vertex -> (VertexHld, VertexHld)
+ AtCoder.Extra.Tree.Hld: type Vertex = Int
+ AtCoder.Extra.Tree.Hld: type VertexHld = Vertex
+ AtCoder.Extra.Tree.TreeMonoid: Commute :: Commutativity
+ AtCoder.Extra.Tree.TreeMonoid: NonCommute :: Commutativity
+ AtCoder.Extra.Tree.TreeMonoid: data Commutativity
+ AtCoder.Extra.Tree.TreeMonoid: data TreeMonoid a s
+ AtCoder.Extra.Tree.TreeMonoid: exchange :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m a
+ AtCoder.Extra.Tree.TreeMonoid: fromEdges :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => Hld -> Commutativity -> Vector (Vertex, Vertex, a) -> m (TreeMonoid a (PrimState m))
+ AtCoder.Extra.Tree.TreeMonoid: fromVerts :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => Hld -> Commutativity -> Vector a -> m (TreeMonoid a (PrimState m))
+ AtCoder.Extra.Tree.TreeMonoid: instance GHC.Classes.Eq AtCoder.Extra.Tree.TreeMonoid.Commutativity
+ AtCoder.Extra.Tree.TreeMonoid: instance GHC.Show.Show AtCoder.Extra.Tree.TreeMonoid.Commutativity
+ AtCoder.Extra.Tree.TreeMonoid: modify :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> (a -> a) -> Int -> m ()
+ AtCoder.Extra.Tree.TreeMonoid: modifyM :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> (a -> m a) -> Int -> m ()
+ AtCoder.Extra.Tree.TreeMonoid: prod :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> Vertex -> m a
+ AtCoder.Extra.Tree.TreeMonoid: prodSubtree :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a
+ AtCoder.Extra.Tree.TreeMonoid: read :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a
+ AtCoder.Extra.Tree.TreeMonoid: type Vertex = Int
+ AtCoder.Extra.Tree.TreeMonoid: type VertexHld = Vertex
+ AtCoder.Extra.Tree.TreeMonoid: write :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m ()
+ AtCoder.Extra.WaveletMatrix: WaveletMatrix :: !RawWaveletMatrix -> !Vector Int -> WaveletMatrix
+ AtCoder.Extra.WaveletMatrix: [rawWM] :: WaveletMatrix -> !RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix: [xDictWM] :: WaveletMatrix -> !Vector Int
+ AtCoder.Extra.WaveletMatrix: access :: WaveletMatrix -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: assocsIn :: WaveletMatrix -> Int -> Int -> [(Int, Int)]
+ AtCoder.Extra.WaveletMatrix: build :: Vector Int -> WaveletMatrix
+ AtCoder.Extra.WaveletMatrix: data WaveletMatrix
+ AtCoder.Extra.WaveletMatrix: descAssocsIn :: WaveletMatrix -> Int -> Int -> [(Int, Int)]
+ AtCoder.Extra.WaveletMatrix: ikthLargestIn :: WaveletMatrix -> Int -> Int -> Int -> Maybe (Int, Int)
+ AtCoder.Extra.WaveletMatrix: ikthSmallestIn :: WaveletMatrix -> Int -> Int -> Int -> Maybe (Int, Int)
+ AtCoder.Extra.WaveletMatrix: kthLargestIn :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: kthSmallestIn :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: lookupGE :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: lookupGT :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: lookupLE :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: lookupLT :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: rank :: WaveletMatrix -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix: rankBetween :: WaveletMatrix -> Int -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix: select :: WaveletMatrix -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: selectIn :: WaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: selectKth :: WaveletMatrix -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix: selectKthIn :: WaveletMatrix -> Int -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.BitVector: BitVector :: !Vector Bit -> !Vector Int -> BitVector
+ AtCoder.Extra.WaveletMatrix.BitVector: [bitsBv] :: BitVector -> !Vector Bit
+ AtCoder.Extra.WaveletMatrix.BitVector: [csumBv] :: BitVector -> !Vector Int
+ AtCoder.Extra.WaveletMatrix.BitVector: build :: Vector Bit -> BitVector
+ AtCoder.Extra.WaveletMatrix.BitVector: csumInPlace :: PrimMonad m => MVector (PrimState m) Int -> Vector Bit -> m Int
+ AtCoder.Extra.WaveletMatrix.BitVector: data BitVector
+ AtCoder.Extra.WaveletMatrix.BitVector: instance GHC.Classes.Eq AtCoder.Extra.WaveletMatrix.BitVector.BitVector
+ AtCoder.Extra.WaveletMatrix.BitVector: instance GHC.Show.Show AtCoder.Extra.WaveletMatrix.BitVector.BitVector
+ AtCoder.Extra.WaveletMatrix.BitVector: rank0 :: BitVector -> Int -> Int
+ AtCoder.Extra.WaveletMatrix.BitVector: rank1 :: BitVector -> Int -> Int
+ AtCoder.Extra.WaveletMatrix.BitVector: select0 :: BitVector -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.BitVector: select1 :: BitVector -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.BitVector: selectKthIn0 :: BitVector -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.BitVector: selectKthIn1 :: BitVector -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.BitVector: wordSize :: Int
+ AtCoder.Extra.WaveletMatrix.Raw: RawWaveletMatrix :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !Vector BitVector -> !Vector Int -> RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix.Raw: [bitsRwm] :: RawWaveletMatrix -> !Vector BitVector
+ AtCoder.Extra.WaveletMatrix.Raw: [heightRwm] :: RawWaveletMatrix -> {-# UNPACK #-} !Int
+ AtCoder.Extra.WaveletMatrix.Raw: [lengthRwm] :: RawWaveletMatrix -> {-# UNPACK #-} !Int
+ AtCoder.Extra.WaveletMatrix.Raw: [nZerosRwm] :: RawWaveletMatrix -> !Vector Int
+ AtCoder.Extra.WaveletMatrix.Raw: access :: RawWaveletMatrix -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: assocsIn :: RawWaveletMatrix -> Int -> Int -> [(Int, Int)]
+ AtCoder.Extra.WaveletMatrix.Raw: assocsWith :: RawWaveletMatrix -> Int -> Int -> (Int -> Int) -> [(Int, Int)]
+ AtCoder.Extra.WaveletMatrix.Raw: build :: HasCallStack => Int -> Vector Int -> RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix.Raw: data RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix.Raw: descAssocsIn :: RawWaveletMatrix -> Int -> Int -> [(Int, Int)]
+ AtCoder.Extra.WaveletMatrix.Raw: descAssocsInWith :: RawWaveletMatrix -> Int -> Int -> (Int -> Int) -> [(Int, Int)]
+ AtCoder.Extra.WaveletMatrix.Raw: ikthLargestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe (Int, Int)
+ AtCoder.Extra.WaveletMatrix.Raw: ikthSmallestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe (Int, Int)
+ AtCoder.Extra.WaveletMatrix.Raw: instance GHC.Classes.Eq AtCoder.Extra.WaveletMatrix.Raw.RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix.Raw: instance GHC.Show.Show AtCoder.Extra.WaveletMatrix.Raw.RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix.Raw: kthLargestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: kthSmallestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: lookupGE :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: lookupGT :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: lookupLE :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: lookupLT :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: rank :: RawWaveletMatrix -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix.Raw: rankBetween :: RawWaveletMatrix -> Int -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix.Raw: rankLT :: RawWaveletMatrix -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix.Raw: select :: RawWaveletMatrix -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: selectIn :: RawWaveletMatrix -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: selectKth :: RawWaveletMatrix -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: selectKthIn :: RawWaveletMatrix -> Int -> Int -> Int -> Int -> Maybe Int
+ AtCoder.Extra.WaveletMatrix.Raw: unsafeIKthLargestIn :: RawWaveletMatrix -> Int -> Int -> Int -> (Int, Int)
+ AtCoder.Extra.WaveletMatrix.Raw: unsafeIKthSmallestIn :: RawWaveletMatrix -> Int -> Int -> Int -> (Int, Int)
+ AtCoder.Extra.WaveletMatrix.Raw: unsafeKthLargestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix.Raw: unsafeKthSmallestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Int
+ AtCoder.Extra.WaveletMatrix2d: WaveletMatrix2d :: !RawWaveletMatrix -> !Vector (Int, Int) -> !Vector Int -> !Vector (SegTree s a) -> !a -> a -> WaveletMatrix2d s a
+ AtCoder.Extra.WaveletMatrix2d: [invWm2d] :: WaveletMatrix2d s a -> !a -> a
+ AtCoder.Extra.WaveletMatrix2d: [rawWmWm2d] :: WaveletMatrix2d s a -> !RawWaveletMatrix
+ AtCoder.Extra.WaveletMatrix2d: [segTreesWm2d] :: WaveletMatrix2d s a -> !Vector (SegTree s a)
+ AtCoder.Extra.WaveletMatrix2d: [xyDictWm2d] :: WaveletMatrix2d s a -> !Vector (Int, Int)
+ AtCoder.Extra.WaveletMatrix2d: [yDictWm2d] :: WaveletMatrix2d s a -> !Vector Int
+ AtCoder.Extra.WaveletMatrix2d: allProd :: (HasCallStack, Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> m a
+ AtCoder.Extra.WaveletMatrix2d: build :: (PrimMonad m, Monoid a, Unbox a) => (a -> a) -> Vector (Int, Int, a) -> m (WaveletMatrix2d (PrimState m) a)
+ AtCoder.Extra.WaveletMatrix2d: data WaveletMatrix2d s a
+ AtCoder.Extra.WaveletMatrix2d: modify :: (HasCallStack, Monoid a, Unbox a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> (a -> a) -> (Int, Int) -> m ()
+ AtCoder.Extra.WaveletMatrix2d: new :: (PrimMonad m, Monoid a, Unbox a) => (a -> a) -> Vector (Int, Int) -> m (WaveletMatrix2d (PrimState m) a)
+ AtCoder.Extra.WaveletMatrix2d: prod :: (HasCallStack, Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> Int -> Int -> Int -> Int -> m a
+ AtCoder.Extra.WaveletMatrix2d: prodMaybe :: (Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> Int -> Int -> Int -> Int -> m (Maybe a)
+ AtCoder.Extra.WaveletMatrix2d: read :: (HasCallStack, Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> (Int, Int) -> m a
+ AtCoder.Extra.WaveletMatrix2d: write :: (HasCallStack, Monoid a, Unbox a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> (Int, Int) -> a -> m ()
+ AtCoder.Internal.Csr: Csr :: {-# UNPACK #-} !Int -> {-# UNPACK #-} !Int -> !Vector Int -> !Vector Int -> !Vector w -> Csr w
+ AtCoder.Internal.Csr: [adjCsr] :: Csr w -> !Vector Int
+ AtCoder.Internal.Csr: [mCsr] :: Csr w -> {-# UNPACK #-} !Int
+ AtCoder.Internal.Csr: [nCsr] :: Csr w -> {-# UNPACK #-} !Int
+ AtCoder.Internal.Csr: [startCsr] :: Csr w -> !Vector Int
+ AtCoder.Internal.Csr: [wCsr] :: Csr w -> !Vector w
+ AtCoder.Internal.Csr: build1 :: HasCallStack => Int -> Vector (Int, Int) -> Csr Int
+ AtCoder.LazySegTree: exchange :: (HasCallStack, PrimMonad m, SegAct f a, Unbox f, Monoid a, Unbox a) => LazySegTree (PrimState m) f a -> Int -> a -> m a
+ AtCoder.SegTree: exchange :: (HasCallStack, PrimMonad m, Monoid a, Unbox a) => SegTree (PrimState m) a -> Int -> a -> m a
- AtCoder.Extra.Monoid.RangeAdd: act :: Num a => RangeAdd a -> a -> a
+ AtCoder.Extra.Monoid.RangeAdd: act :: Semigroup a => RangeAdd a -> a -> a
- AtCoder.Internal.Csr: adj :: (HasCallStack, Unbox w) => Csr w -> Int -> Vector Int
+ AtCoder.Internal.Csr: adj :: HasCallStack => Csr w -> Int -> Vector Int
- AtCoder.Internal.Csr: eAdj :: (HasCallStack, Unbox w) => Csr w -> Int -> Vector (Int, Int)
+ AtCoder.Internal.Csr: eAdj :: HasCallStack => Csr w -> Int -> Vector (Int, Int)
Files
- CHANGELOG.md +11/−3
- README.md +2/−2
- ac-library-hs.cabal +45/−3
- benchmarks/Bench/AddMod.hs +1/−1
- benchmarks/Bench/Matrix.hs +87/−0
- benchmarks/Bench/ModInt.hs +23/−0
- benchmarks/BenchLib/Matrix.hs +394/−0
- benchmarks/BenchLib/MulMod/BarrettWideWord.hs +2/−1
- benchmarks/BenchLib/MulMod/Montgomery.hs +3/−3
- benchmarks/Main.hs +8/−5
- src/AtCoder/Convolution.hs +2/−2
- src/AtCoder/Dsu.hs +16/−16
- src/AtCoder/Extra/Bisect.hs +297/−0
- src/AtCoder/Extra/Graph.hs +147/−0
- src/AtCoder/Extra/HashMap.hs +346/−0
- src/AtCoder/Extra/IntMap.hs +338/−0
- src/AtCoder/Extra/IntSet.hs +391/−0
- src/AtCoder/Extra/IntervalMap.hs +462/−0
- src/AtCoder/Extra/Math.hs +34/−18
- src/AtCoder/Extra/Monoid.hs +23/−12
- src/AtCoder/Extra/Monoid/Affine1.hs +40/−14
- src/AtCoder/Extra/Monoid/Mat2x2.hs +202/−0
- src/AtCoder/Extra/Monoid/RangeAdd.hs +38/−22
- src/AtCoder/Extra/Monoid/RangeAddId.hs +0/−95
- src/AtCoder/Extra/Monoid/RangeSet.hs +18/−10
- src/AtCoder/Extra/Monoid/RangeSetId.hs +0/−124
- src/AtCoder/Extra/Monoid/RollingHash.hs +121/−0
- src/AtCoder/Extra/Monoid/V2.hs +81/−0
- src/AtCoder/Extra/MultiSet.hs +280/−0
- src/AtCoder/Extra/Pdsu.hs +306/−0
- src/AtCoder/Extra/Semigroup/Matrix.hs +264/−0
- src/AtCoder/Extra/Semigroup/Permutation.hs +114/−0
- src/AtCoder/Extra/Tree.hs +207/−0
- src/AtCoder/Extra/Tree/Hld.hs +512/−0
- src/AtCoder/Extra/Tree/TreeMonoid.hs +297/−0
- src/AtCoder/Extra/WaveletMatrix.hs +407/−0
- src/AtCoder/Extra/WaveletMatrix/BitVector.hs +179/−0
- src/AtCoder/Extra/WaveletMatrix/Raw.hs +651/−0
- src/AtCoder/Extra/WaveletMatrix2d.hs +277/−0
- src/AtCoder/FenwickTree.hs +10/−10
- src/AtCoder/Internal/Assert.hs +1/−1
- src/AtCoder/Internal/Barrett.hs +6/−6
- src/AtCoder/Internal/Buffer.hs +54/−59
- src/AtCoder/Internal/Convolution.hs +1/−1
- src/AtCoder/Internal/Csr.hs +47/−16
- src/AtCoder/Internal/GrowVec.hs +40/−40
- src/AtCoder/Internal/Math.hs +19/−3
- src/AtCoder/Internal/MinHeap.hs +18/−18
- src/AtCoder/Internal/Queue.hs +37/−35
- src/AtCoder/Internal/Scc.hs +55/−21
- src/AtCoder/Internal/String.hs +33/−4
- src/AtCoder/LazySegTree.hs +40/−17
- src/AtCoder/Math.hs +23/−4
- src/AtCoder/MaxFlow.hs +82/−12
- src/AtCoder/MinCostFlow.hs +36/−4
- src/AtCoder/ModInt.hs +40/−37
- src/AtCoder/Scc.hs +7/−1
- src/AtCoder/SegTree.hs +70/−13
- src/AtCoder/String.hs +37/−20
- src/AtCoder/TwoSat.hs +1/−1
- test/Main.hs +29/−2
- test/Tests/Extra/Bisect.hs +114/−0
- test/Tests/Extra/Graph.hs +52/−0
- test/Tests/Extra/HashMap.hs +171/−0
- test/Tests/Extra/IntMap.hs +176/−0
- test/Tests/Extra/IntSet.hs +150/−0
- test/Tests/Extra/IntervalMap.hs +209/−0
- test/Tests/Extra/Monoid.hs +97/−49
- test/Tests/Extra/MultiSet.hs +218/−0
- test/Tests/Extra/Semigroup/Matrix.hs +43/−0
- test/Tests/Extra/Semigroup/Permutation.hs +71/−0
- test/Tests/Extra/WaveletMatrix.hs +237/−0
- test/Tests/Extra/WaveletMatrix/BitVector.hs +84/−0
- test/Tests/Extra/WaveletMatrix/Raw.hs +271/−0
- test/Tests/Extra/WaveletMatrix2d.hs +119/−0
- test/Tests/MaxFlow.hs +1/−1
- test/Tests/Scc.hs +0/−2
- test/Tests/Util.hs +8/−1
CHANGELOG.md view
@@ -1,8 +1,16 @@ # Revision history for acl-hs +## 1.1.0.0 -- Jan 2025++- Removed `RangeSetId` and `RangeAddId` from `AtCoder.Extra.Monoid`.+- Implemented `SegAct` for `RangeSet`, `RangeAdd` and `Max`, `Min`.+- Added `segActWithLength` to `SegAct`.+- Added `build1` to `AtCoder.Internal.Csr`.+- Added a bunch of extra modules.+ ## 1.0.0.0 -- Dec 2024 -* First version.-* ACL-compatible modules.-* Extra module of `Math` (binary exponentiation) and `Monoid` (`SegAct` instances).+- First version.+- Added ACL-compatible modules.+- Added Extra module of `Math` (binary exponentiation) and `Monoid` (`SegAct` instances).
README.md view
@@ -5,8 +5,8 @@ ## Notes - The library is mainly for AtCoder and only GHC 9.8.4 is guaranteed to be supported.-- The `Internal` module is unstable and does not follow PVP.-- The `Extra` module provides with extra contents not in the original `ac-library`. Note that they're less tested.+- Functions primarily use half-open interval \([l, r)\).+- The extra module contains additional utilities beyond the original C++ library. ## Usage
ac-library-hs.cabal view
@@ -4,12 +4,15 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 1.0.0.1+version: 1.1.0.0 synopsis: Data structures and algorithms description: Haskell port of [ac-library](https://github.com/atcoder/ac-library), a library for competitive programming on [AtCoder](https://atcoder.jp/). + - Functions primarily use half-open interval \([l, r)\).+ - The extra module contains additional utilities beyond the original C++ library.+ category: Algorithms, Data Structures license: CC0-1.0 license-file: LICENSE@@ -70,13 +73,31 @@ exposed-modules: AtCoder.Convolution AtCoder.Dsu+ AtCoder.Extra.Bisect+ AtCoder.Extra.HashMap+ AtCoder.Extra.IntervalMap+ AtCoder.Extra.IntMap+ AtCoder.Extra.IntSet+ AtCoder.Extra.Graph+ AtCoder.Extra.Tree+ AtCoder.Extra.Tree.Hld+ AtCoder.Extra.Tree.TreeMonoid AtCoder.Extra.Math AtCoder.Extra.Monoid AtCoder.Extra.Monoid.Affine1+ AtCoder.Extra.Monoid.Mat2x2 AtCoder.Extra.Monoid.RangeAdd- AtCoder.Extra.Monoid.RangeAddId AtCoder.Extra.Monoid.RangeSet- AtCoder.Extra.Monoid.RangeSetId+ AtCoder.Extra.Monoid.RollingHash+ AtCoder.Extra.Monoid.V2+ AtCoder.Extra.MultiSet+ AtCoder.Extra.Semigroup.Matrix+ AtCoder.Extra.Semigroup.Permutation+ AtCoder.Extra.Pdsu+ AtCoder.Extra.WaveletMatrix+ AtCoder.Extra.WaveletMatrix.BitVector+ AtCoder.Extra.WaveletMatrix.Raw+ AtCoder.Extra.WaveletMatrix2d AtCoder.FenwickTree AtCoder.Internal.Assert AtCoder.Internal.Barrett@@ -118,8 +139,21 @@ other-modules: Tests.Convolution Tests.Dsu+ Tests.Extra.Bisect+ Tests.Extra.Graph+ Tests.Extra.HashMap+ Tests.Extra.IntervalMap+ Tests.Extra.IntMap+ Tests.Extra.IntSet Tests.Extra.Math Tests.Extra.Monoid+ Tests.Extra.MultiSet+ Tests.Extra.Semigroup.Matrix+ Tests.Extra.Semigroup.Permutation+ Tests.Extra.WaveletMatrix+ Tests.Extra.WaveletMatrix.BitVector+ Tests.Extra.WaveletMatrix.Raw+ Tests.Extra.WaveletMatrix2d Tests.FenwickTree Tests.Internal.Bit Tests.Internal.Buffer@@ -146,6 +180,7 @@ main-is: Main.hs build-depends: , ac-library-hs+ , containers , hspec , mtl , QuickCheck@@ -157,6 +192,7 @@ , tasty-quickcheck , tasty-rerun , transformers+ , unordered-containers benchmark ac-library-hs-benchmark import: warnings@@ -167,8 +203,11 @@ hs-source-dirs: benchmarks other-modules: Bench.AddMod+ Bench.Matrix+ Bench.ModInt Bench.PowMod BenchLib.AddMod+ BenchLib.Matrix BenchLib.ModInt.ModIntNats BenchLib.ModInt.Modulus BenchLib.MulMod.Barrett64@@ -180,8 +219,10 @@ , ac-library-hs , base , criterion+ , mtl , random , tagged+ , transformers test-suite benchlib-test import: warnings@@ -204,6 +245,7 @@ , hspec , mtl , QuickCheck+ -- , quickcheck-instances , random , tagged , tasty
benchmarks/Bench/AddMod.hs view
@@ -6,7 +6,7 @@ import BenchLib.AddMod import Criterion import Data.Vector.Unboxed qualified as VU-import Data.Word (Word32, Word64)+import Data.Word (Word32) import System.Random n :: Int
+ benchmarks/Bench/Matrix.hs view
@@ -0,0 +1,87 @@+module Bench.Matrix (benches) where++import AtCoder.ModInt qualified as M+import AtCoder.Extra.Semigroup.Matrix qualified as ACMAT+import AtCoder.Extra.Math qualified as ACEM+import BenchLib.Matrix qualified as Mat+import Control.Monad.State.Class (MonadState, state)+import Control.Monad.Trans.State.Strict (evalState, runState)+import Criterion+import Data.Semigroup (Semigroup (..))+import Data.Vector qualified as V+import Data.Vector.Unboxed qualified as VU+import System.Random++testSize :: Int+testSize = 10000++m :: Int+m = 998244353++randomMatrix :: (MonadState StdGen m) => m (Mat.Matrix Int, Int)+randomMatrix = do+ h <- state $ uniformR (1, 16)+ nextMatrix h++nextMatrix :: (MonadState StdGen m) => Int -> m (Mat.Matrix Int, Int)+nextMatrix h = do+ w <- state $ uniformR (1, 16)+ vec <- VU.replicateM (h * w) $ state (uniformR (0, m - 1))+ pure (Mat.new h w vec, w)++randomSquareACLMatrix :: (MonadState StdGen m) => Int -> m (ACMAT.Matrix Int)+randomSquareACLMatrix n = do+ vec <- VU.replicateM (n * n) $ state (uniformR (0, m - 1))+ pure $ ACMAT.new n n vec++benches :: Benchmark+benches =+ bgroup+ "Matrix"+ [ bench "mul1" $ whnf (V.foldl1' Mat.mul1) randomMatrixInput,+ bench "mul2" $ whnf (V.foldl1' Mat.mul2) randomMatrixInput,+ bench "mul3_1" $ whnf (V.foldl1' Mat.mul3_1) randomMatrixInput,+ bench "mul3_2" $ whnf (V.foldl1' Mat.mul3_2) randomMatrixInput,+ bench "mul3_3" $ whnf (V.foldl1' Mat.mul3_3) randomMatrixInput,+ bench "mulMod1" $ whnf (V.foldl1' (Mat.mulMod1 m)) randomMatrixInput,+ bench "mulMod2" $ whnf (V.foldl1' (Mat.mulMod2 m)) randomMatrixInput,+ bench "mulMod3" $ whnf (V.foldl1' (Mat.mulMod3 m)) randomMatrixInput,+ bench "mulMod4" $ whnf (V.foldl1' (Mat.mulMod4 m)) randomMatrixInput,+ bench "mulMod5" $ whnf (V.foldl1' (Mat.mulMod5 m)) randomMatrixInput,+ bench "mulMint1" $ whnf (V.foldl1' Mat.mulMint1) randomMintMatrixInput,+ bench "mulMint2" $ whnf (V.foldl1' Mat.mulMint2) randomMintMatrixInput,+ bench "mulMint3" $ whnf (V.foldl1' Mat.mulMint3) randomMintMatrixInput,+ -- mul (ACL)+ bench "mul_ACL" $ whnf (V.foldl1' ACMAT.mul) randomMatrixInputACL,+ bench "mulMod_ACL" $ whnf (V.foldl1' (ACMAT.mulMod m)) randomMatrixInputACL,+ -- pow mod (ACL only)+ bench "powMod_ACL" $ whnf (VU.foldl' (flip (ACMAT.powMod m)) squareMat) randomVec,+ bench "powMintACL_stimes" $ whnf (VU.foldl' (flip stimes) squareMatMint) randomVec,+ bench "powMintACL_stimes'" $ whnf (VU.foldl' (flip ACEM.stimes') squareMatMint) randomVec,+ bench "powMintACL_powMint" $ whnf (VU.foldl' (flip ACMAT.powMint) squareMatMint) randomVec+ ]+ where+ -- Bench matrix+ randomMatrixInput :: V.Vector (Mat.Matrix Int)+ !randomMatrixInput = evalState (V.unfoldrExactNM testSize nextMatrix (Mat.wM mat0)) gen0+ where+ ((!mat0, !_), !gen0) = runState randomMatrix $ mkStdGen 123456789++ randomMintMatrixInput :: V.Vector (Mat.Matrix (M.ModInt 998244353))+ !randomMintMatrixInput = V.map (Mat.map M.new) randomMatrixInput++ -- ACL matrix+ randomMatrixInputACL :: V.Vector (ACMAT.Matrix Int)+ !randomMatrixInputACL = V.map (\mat -> ACMAT.new (Mat.hM mat) (Mat.wM mat) (Mat.vecM mat)) randomMatrixInput++ squareMat :: ACMAT.Matrix Int+ !squareMat = evalState (randomSquareACLMatrix 17) $ mkStdGen 123456789++ squareMatMint ::ACMAT.Matrix (M.ModInt 998244353)+ !squareMatMint = ACMAT.map M.new squareMat++ -- non-zero random vector+ randomVec :: VU.Vector Int+ !randomVec =+ VU.map ((+ 1) . fromIntegral) $+ VU.unfoldrExactN 100 (genWord64R (m - 2)) (mkStdGen 123456789)
+ benchmarks/Bench/ModInt.hs view
@@ -0,0 +1,23 @@+module Bench.ModInt (benches) where++import AtCoder.ModInt qualified as M+import BenchLib.PowMod qualified as PowMod+import BenchLib.ModInt.ModIntNats qualified as MN+import Criterion+import Data.Vector.Unboxed qualified as VU+import System.Random++benches :: Benchmark+benches =+ bgroup+ "modInt"+ [++ ]+ where+ n = 10000+ randomVec :: VU.Vector Int+ randomVec =+ VU.map fromIntegral $+ VU.unfoldrExactN n (genWord64R (998244383 - 2)) (mkStdGen 123456789)+
+ benchmarks/BenchLib/Matrix.hs view
@@ -0,0 +1,394 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE RecordWildCards #-}++module BenchLib.Matrix+ ( Matrix (..),+ new,+ map,+ mulToCol,+ mulToColModInt,+ mul1,+ mul2,+ mul3_1,+ mul3_2,+ mul3_3,+ mulMod1,+ mulMod2,+ mulMod3,+ mulMod4,+ mulMod5,+ mulMint1,+ mulMint2,+ mulMint3,+ )+where++import AtCoder.Internal.Assert qualified as ACIA+import AtCoder.Internal.Barrett qualified as BT+import AtCoder.ModInt qualified as M+import Data.Vector qualified as V+import Data.Vector.Generic qualified as VG+import Data.Vector.Unboxed qualified as VU+import Data.Word (Word64)+import GHC.Exts (Proxy#, proxy#)+import GHC.Stack (HasCallStack)+import GHC.TypeNats (KnownNat, natVal, natVal')+import Prelude hiding (map)++data Matrix a = Matrix+ { hM :: {-# UNPACK #-} !Int,+ wM :: {-# UNPACK #-} !Int,+ vecM :: !(VU.Vector a)+ }+ deriving (Show, Eq)++type Col a = VU.Vector a++{-# INLINE new #-}+new :: (HasCallStack, VU.Unbox a) => Int -> Int -> VU.Vector a -> Matrix a+new h w vec+ | VU.length vec /= h * w = error "AtCoder.Extra.Matrix: size mismatch"+ | otherwise = Matrix h w vec++{-# INLINE map #-}+map :: (VU.Unbox a, VU.Unbox b) => (a -> b) -> Matrix a -> Matrix b+map f Matrix {..} = Matrix hM wM $ VU.map f vecM++{-# INLINE mulToCol #-}+mulToCol :: (Num a, VU.Unbox a) => Matrix a -> Col a -> Col a+mulToCol Matrix {..} !col = VU.convert $ V.map (VU.sum . VU.zipWith (*) col) rows+ where+ !n = VU.length col+ !_ = ACIA.runtimeAssert (n == wM) "AtCoder.Extra.Matrix.mulToCol: size mismatch"+ rows = V.unfoldrExactN hM (VU.splitAt wM) vecM++{-# INLINE mulToColModInt #-}+mulToColModInt :: forall m. (KnownNat m) => Matrix (M.ModInt m) -> Col (M.ModInt m) -> Col (M.ModInt m)+mulToColModInt Matrix {..} !col = VU.convert $ V.map (VU.foldl' (+) (M.unsafeNew 0) . VU.zipWith mulMod col) rows+ where+ !_ = ACIA.runtimeAssert (VU.length col == wM) "AtCoder.Extra.Matrix.mulToColModInt: size mismatch"+ !bt = BT.new32 $ fromIntegral (natVal' (proxy# @m))+ rows = V.unfoldrExactN hM (VU.splitAt wM) vecM+ mulMod (M.ModInt x) (M.ModInt y) = M.unsafeNew . fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)++{-# INLINE mul1 #-}+mul1 :: (Num e, VU.Unbox e) => Matrix e -> Matrix e -> Matrix e+mul1 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f row col = VU.sum $ VU.zipWith (*) (rows1 VG.! row) (cols2 VG.! col)+ h = hM a+ w = wM a+ vecA = vecM a+ h' = hM b+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"+ rows1 = V.unfoldrExactN h (VU.splitAt w) vecA+ cols2 = V.generate w' $ \col -> VU.unfoldrExactN h' (\i -> (VG.unsafeIndex vecB i, i + w')) col++{-# INLINE mul2 #-}+mul2 :: (Num e, VU.Unbox e) => Matrix e -> Matrix e -> Matrix e+mul2 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f row col = VU.sum $ VU.imap (\iRow x -> x * VG.unsafeIndex vecB (col + iRow * w')) (rows1 VG.! row)+ h = hM a+ w = wM a+ vecA = vecM a+ h' = hM b+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"+ rows1 = V.unfoldrExactN h (VU.splitAt w) vecA++{-# INLINE mul3_1 #-}+mul3_1 :: (Num e, VU.Unbox e) => Matrix e -> Matrix e -> Matrix e+mul3_1 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f row col = VU.sum $ VU.imap (\iRow x -> x * VG.unsafeIndex vecB (col + iRow * w')) (VU.unsafeSlice (w * row) w vecA)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mul3_2 #-}+mul3_2 :: (Num e, VU.Unbox e) => Matrix e -> Matrix e -> Matrix e+mul3_2 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !y = VU.sum $ VU.imap (\iRow x -> x * VG.unsafeIndex vecB (col + iRow * w')) (VU.unsafeSlice (w * row) w vecA)+ in if col + 1 >= w'+ then (y, (row + 1, 0))+ else (y, (row, col + 1))+ )+ (0, 0)+ where+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mul3_3 #-}+mul3_3 :: (Num e, VU.Unbox e) => Matrix e -> Matrix e -> Matrix e+mul3_3 !a !b = Matrix h w' $ VU.generate (h * w') $ \i ->+ let (!row, !col) = i `quotRem` w'+ in VU.sum $ VU.imap (\iRow x -> x * VG.unsafeIndex vecB (col + iRow * w')) (VU.unsafeSlice (w * row) w vecA)+ where+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMod1 #-}+mulMod1 :: Int -> Matrix Int -> Matrix Int -> Matrix Int+mulMod1 !m !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f row col = VU.foldl1' addMod $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ addMod x y = (x + y) `mod` m+ mulMod x y = (x * y) `mod` m+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMod2 #-}+mulMod2 :: Int -> Matrix Int -> Matrix Int -> Matrix Int+mulMod2 !m !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f row col = VU.foldl1' addMod $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ -- very slow+ addMod x y+ | x + y >= m = x + y - m+ | otherwise = x + y+ mulMod x y = (x * y) `mod` m+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMod3 #-}+mulMod3 :: Int -> Matrix Int -> Matrix Int -> Matrix Int+mulMod3 !m !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ !bt = BT.new32 $ fromIntegral m+ f row col = VU.foldl1' addMod $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ addMod x y = (x + y) `mod` m+ mulMod x y = fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMod4 #-}+mulMod4 :: Int -> Matrix Int -> Matrix Int -> Matrix Int+mulMod4 !m !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ !bt = BT.new32 $ fromIntegral m+ f row col = VU.foldl1' addMod $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ addMod x y = (x + y) `rem` m+ mulMod x y = fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMod5 #-}+mulMod5 :: Int -> Matrix Int -> Matrix Int -> Matrix Int+mulMod5 !m !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ !bt = BT.new32 $ fromIntegral m+ f row col = VU.foldl1' addMod $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ addMod x y+ | x + y >= m = x + y - m+ | otherwise = x + y+ mulMod x y = fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMint1 #-}+mulMint1 :: forall a. (KnownNat a) => Matrix (M.ModInt a) -> Matrix (M.ModInt a) -> Matrix (M.ModInt a)+mulMint1 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f :: Int -> Int -> M.ModInt a+ f row col = VU.sum $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ mulMod :: M.ModInt a -> M.ModInt a -> M.ModInt a+ mulMod = (*)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++{-# INLINE mulMint2 #-}+mulMint2 :: forall a. (KnownNat a) => Matrix (M.ModInt a) -> Matrix (M.ModInt a) -> Matrix (M.ModInt a)+mulMint2 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ !bt = BT.new32 $ fromIntegral (natVal' (proxy# @a))+ f :: Int -> Int -> M.ModInt a+ f row col = VU.sum $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ mulMod :: M.ModInt a -> M.ModInt a -> M.ModInt a+ mulMod (M.ModInt x) (M.ModInt y) = M.unsafeNew . fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++-- REMARK: This is very unsafe in that it can overflow (mod^2 * n)+{-# INLINE mulMint3 #-}+mulMint3 :: forall a. (KnownNat a) => Matrix (M.ModInt a) -> Matrix (M.ModInt a) -> Matrix (M.ModInt a)+mulMint3 !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ !bt = BT.new32 $ fromIntegral (natVal' (proxy# @a))+ f :: Int -> Int -> M.ModInt a+ f row col = M.new64 . VU.sum $ VU.imap (\iRow x -> mulMod x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ mulMod :: M.ModInt a -> M.ModInt a -> Word64+ mulMod (M.ModInt x) (M.ModInt y) = BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"
benchmarks/BenchLib/MulMod/BarrettWideWord.hs view
@@ -24,10 +24,11 @@ imBarrett :: {-# UNPACK #-} !Word64 } --- | Creates barret reduction for modulus \(m\).+-- | Creates a `Barrett` for modulus value \(m\) of type `Word32`. new32 :: Word32 -> Barrett new32 m = Barrett m $ maxBound @Word64 `div` (fromIntegral m :: Word64) + 1 +-- | Creates a `Barrett` for modulus value \(m\) of type `Word64`. new64 :: Word64 -> Barrett new64 m = Barrett (fromIntegral m) $ maxBound @Word64 `div` m + 1
benchmarks/BenchLib/MulMod/Montgomery.hs view
@@ -17,8 +17,8 @@ import Data.Bits (bit, (!>>.)) import Data.Word (Word32, Word64) --- | Fast modular multiplication by Montgomery multiplication. The modulus value has to be odd--- to be fast.+-- | Fast modular multiplication by Montgomery multiplication. The modulus value must be odd for+-- the speed. data Montgomery = Montgomery { mMontgomery :: {-# UNPACK #-} !Word64, -- | R2 == (2^64) % MOD;@@ -27,7 +27,7 @@ negInvMontgomery :: {-# UNPACK #-} !Word32 } --- | Creates `Montgomery` for modulus @m@.+-- | Creates a `Montgomery` for modulus @m@. new :: Word64 -> Montgomery new m = let !negInv = inner 0 0 1 0
benchmarks/Main.hs view
@@ -3,7 +3,9 @@ module Main where import Bench.AddMod qualified+import Bench.Matrix qualified import Bench.MulMod qualified+import Bench.ModInt qualified import Bench.PowMod qualified import Criterion.Main @@ -13,9 +15,10 @@ main :: IO () main = defaultMain- -- TODO: generate graph by benchmark group?- [ -- Bench.MulMod.benches32,- -- Bench.MulMod.benches64,- -- Bench.AddMod.benches- Bench.PowMod.benches+ -- TODO: generate criterion graph by benchmark group?+ [ Bench.MulMod.benches,+ Bench.ModInt.benches,+ Bench.AddMod.benches,+ Bench.PowMod.benches,+ Bench.Matrix.benches ]
src/AtCoder/Convolution.hs view
@@ -14,7 +14,7 @@ -- >>> import Data.Proxy (Proxy) -- >>> import Data.Vector.Unboxed qualified as VU ----- It's handy to define specific items for interested modulus values:+-- Define specific modulus items: -- -- >>> type Mint = M.ModInt998244353 -- >>> let modInt :: Int -> Mint; modInt = M.new@@ -26,7 +26,7 @@ -- >>> C.convolution a b -- [5,16,34,60,61,52,32] ----- You can also target any @'Integral' a@ (with some runtime overhead for conversion to modint):+-- You can also target any @'Integral' a@ with `convolutionRaw`: -- -- >>> let a = VU.fromList @Int [1, 2, 3, 4] -- >>> let b = VU.fromList @Int [5, 6, 7, 8]
src/AtCoder/Dsu.hs view
@@ -1,17 +1,17 @@ {-# LANGUAGE RecordWildCards #-} --- | Disjoint set union, also known as Union-Find tree. It processes the following queries in+-- | A disjoint set union, also known as a Union-Find tree. It processes the following queries in -- amortized \(O(\alpha(n))\) time. ----- - Edge addition--- - Deciding whether given two vertices are in the same connected component+-- - Edge addition (`merge`)+-- - Deciding whether given two vertices are in the same connected component (`same`) ----- Each connected component internally has a representative vertex. When two connected components--- are merged by edge addition, one of the two representatives of these connected components--- becomes the representative of the new connected component.+-- Each connected component internally has a representative vertex (`leader`). When two connected+-- components are merged by edge addition (`merge`), one of the two representatives of these+-- connected components becomes the representative (`leader`) of the new connected component. -- -- ==== __Example__--- Create DSU:+-- Create a `Dsu` with four vertices: -- -- >>> import AtCoder.Dsu qualified as Dsu -- >>> dsu <- Dsu.new 4 -- 0 1 2 3@@ -49,15 +49,15 @@ -- * Constructor new, - -- * Merge+ -- * Merging merge, merge_, -- * Leader leader,- same, -- * Component information+ same, size, groups, )@@ -73,13 +73,13 @@ import Data.Vector.Unboxed.Mutable qualified as VUM import GHC.Stack (HasCallStack) --- | Disjoint set union. Akso known as Union-Find tree.+-- | A disjoint set union. Akso known as Union-Find tree. -- -- @since 1.0.0.0 data Dsu s = Dsu- { -- | 1.0.0 The number of nodes.+ { -- | The number of nodes. --- -- @since+ -- @since 1.0.0.0 nDsu :: {-# UNPACK #-} !Int, -- | For root (leader) nodes it stores their size as a negative number. For child nodes it -- stores their parent node index.@@ -103,8 +103,8 @@ pure Dsu {..} | otherwise = error $ "new: given negative size (`" ++ show nDsu ++ "`)" --- | Adds an edge @(a, b)@. the vertices @a@ and @b@ were in the same connected component, it--- returns the representative of this connected component. Otherwise, it returns the+-- | Adds an edge \((a, b)\). If the vertices \(a\) and \(b\) are in the same connected component, it+-- returns the representative (`leader`) of this connected component. Otherwise, it returns the -- representative of the new connected component. -- -- ==== Constraints@@ -134,7 +134,7 @@ VGM.modify parentOrSizeDsu (+ sizeY) x pure x --- | `merge` with return value discarded.+-- | `merge` with the return value discarded. -- -- ==== Constraints -- - \(0 \leq a < n\)@@ -207,7 +207,7 @@ sizeLa <- VGM.read parentOrSizeDsu la pure (-sizeLa) --- | Divides the graph into connected components and returns the list of them.+-- | Divides the graph into connected components and returns the vector of them. -- -- More precisely, it returns a vector of the "vector of the vertices in a connected component". -- Both of the orders of the connected components and the vertices are undefined.
+ src/AtCoder/Extra/Bisect.hs view
@@ -0,0 +1,297 @@+-- | Bisection methods and binary search functions. They partition a half-open interval \([l, r)\)+-- into two and return either the left or the right point of the boundary.+--+-- @+-- Y Y Y Y Y N N N N N Y: user predicate holds+-- --------* *---------> X N: user predicate does not hold+-- L R L, R: left, right point of the boundary+-- @+--+-- ==== __Example__+-- Perform index compression:+--+-- >>> import AtCoder.Extra.Bisect+-- >>> import Data.Maybe (fromJust)+-- >>> import Data.Vector.Algorithms.Intro qualified as VAI+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList ([0, 20, 10, 40, 30] :: [Int])+-- >>> let dict = VU.uniq $ VU.modify VAI.sort xs+-- >>> VU.map (fromJust . lowerBound dict) xs+-- [0,2,1,4,3]+--+-- @since 1.1.0.0+module AtCoder.Extra.Bisect+ ( -- * C++-like binary search+ lowerBound,+ lowerBoundIn,+ upperBound,+ upperBoundIn,++ -- * Generic bisection method+ bisectL,+ bisectLM,+ bisectR,+ bisectRM,+ )+where++import AtCoder.Internal.Assert qualified as ACIA+import Data.Functor ((<&>))+import Data.Functor.Identity+import Data.Vector.Generic qualified as VG+import GHC.Stack (HasCallStack)++-- | \(O(\log n)\) Bisection method implementation. Works on a half-open interfal \([l, r)\) .+--+-- @since 1.1.0.0+{-# INLINE bisectLImpl #-}+bisectLImpl :: (HasCallStack, Monad m) => (Int -> m Bool) -> Int -> Int -> m Int+bisectLImpl p l0 = inner (l0 - 1)+ where+ inner l r+ | l + 1 == r = pure l+ | otherwise =+ p mid >>= \case+ True -> inner mid r+ False -> inner l mid+ where+ mid = (l + r) `div` 2++-- | \(O(\log n)\) Bisection method implementation. Works on a half-open interfal \([l, r)\) .+--+-- @since 1.1.0.0+{-# INLINE bisectRImpl #-}+bisectRImpl :: (HasCallStack, Monad m) => (Int -> m Bool) -> Int -> Int -> m Int+bisectRImpl p l = ((+ 1) <$>) . bisectLImpl p l++-- | \(O(\log n)\) Returns the index of the first element \(x\) in the vector such that+-- \(x \ge x_0\), or `Nothing` if no such element exists.+--+-- @+-- Y Y Y Y Y N N N N N Y: (< x0)+-- --------- *---------> X N: (>= x0)+-- R R: returning point+-- @+--+-- ==== __Example__+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList [1, 1, 2, 2, 4, 4]+-- >>> lowerBound xs 1+-- Just 0+--+-- >>> lowerBound xs 2+-- Just 2+--+-- >>> lowerBound xs 3+-- Just 4+--+-- >>> lowerBound xs 4+-- Just 4+--+-- Out of range values:+--+-- >>> lowerBound xs 0+-- Just 0+--+-- >>> lowerBound xs 5+-- Nothing+--+-- @since 1.1.0.0+{-# INLINE lowerBound #-}+lowerBound :: (HasCallStack, VG.Vector v a, Ord a) => v a -> a -> Maybe Int+lowerBound vec = lowerBoundIn 0 (VG.length vec) vec++-- | \(O(\log n)\) Computes the `lowerBound` for a slice of a vector within the interval \([l, r)\).+--+-- - The user predicate evaluates indices in \([l, r)\).+-- - The interval \([l, r)\) is silently clamped to ensure it remains within the bounds \([0, n)\).+--+-- ==== __Example__+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList [10, 10, 20, 20, 40, 40]+-- >>> -- *---*---*+-- >>> lowerBoundIn 2 5 xs 10+-- Just 2+--+-- >>> lowerBoundIn 2 5 xs 20+-- Just 2+--+-- >>> lowerBoundIn 2 5 xs 30+-- Just 4+--+-- >>> lowerBoundIn 2 5 xs 40+-- Just 4+--+-- >>> lowerBoundIn 2 5 xs 50+-- Nothing+--+-- @since 1.1.0.0+{-# INLINE lowerBoundIn #-}+lowerBoundIn :: (VG.Vector v a, Ord a) => Int -> Int -> v a -> a -> Maybe Int+lowerBoundIn l_ r_ vec target+ | ACIA.testInterval l r (VG.length vec) = bisectR l r $ \i -> VG.unsafeIndex vec i < target+ | otherwise = Nothing+ where+ -- clamp+ l = max 0 l_+ r = min (VG.length vec) r_++-- | \(O(\log n)\) Returns the index of the first element \(x\) in the vector such that+-- \(x \gt x_0\), or `Nothing` if no such element exists.+--+-- @+-- Y Y Y Y Y N N N N N Y: (<= x0)+-- --------- *---------> X N: (> x0)+-- R R: returning point+-- @+--+-- ==== __Example__+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList [10, 10, 20, 20, 40, 40]+-- >>> upperBound xs 10+-- Just 2+--+-- >>> upperBound xs 20+-- Just 4+--+-- >>> upperBound xs 30+-- Just 4+--+-- >>> upperBound xs 40+-- Nothing+--+-- Out of range values:+--+-- >>> upperBound xs 0+-- Just 0+--+-- >>> upperBound xs 50+-- Nothing+--+-- @since 1.1.0.0+{-# INLINE upperBound #-}+upperBound :: (HasCallStack, VG.Vector v a, Ord a) => v a -> a -> Maybe Int+upperBound vec = upperBoundIn 0 (VG.length vec) vec++-- | \(O(\log n)\) Computes the `upperBound` for a slice of a vector within the interval \([l, r)\).+--+-- - The user predicate evaluates indices in \([l, r)\).+-- - The interval \([l, r)\) is silently clamped to ensure it remains within the bounds \([0, n)\).+--+-- ==== __Example__+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList [10, 10, 20, 20, 40, 40]+-- >>> -- *---*---*+-- >>> upperBoundIn 2 5 xs 0+-- Just 2+--+-- >>> upperBoundIn 2 5 xs 10+-- Just 2+--+-- >>> upperBoundIn 2 5 xs 20+-- Just 4+--+-- >>> upperBoundIn 2 5 xs 30+-- Just 4+--+-- >>> upperBoundIn 2 5 xs 40+-- Nothing+--+-- >>> upperBoundIn 2 5 xs 50+-- Nothing+--+-- @since 1.1.0.0+{-# INLINE upperBoundIn #-}+upperBoundIn :: (VG.Vector v a, Ord a) => Int -> Int -> v a -> a -> Maybe Int+upperBoundIn l_ r_ vec target+ | ACIA.testInterval l r (VG.length vec) = bisectR l r $ \i -> VG.unsafeIndex vec i <= target+ | otherwise = Nothing+ where+ -- clamp+ l = max 0 l_+ r = min (VG.length vec) r_++-- | \(O(\log n)\) Applies the bisection method on a half-open interval \([l, r)\) and returns the+-- left boundary point, or `Nothing` if no such point exists.+--+-- @+-- Y Y Y Y Y N N N N N Y: user predicate holds+-- --------* ----------> X N: user predicate does not hold+-- L L: the left boundary point returned+-- @+--+-- ==== __Example__+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList [10, 10, 20, 20, 30, 30]+-- >>> let n = VU.length xs+-- >>> bisectL 0 n ((<= 20) . (xs VU.!))+-- Just 3+--+-- >>> bisectL 0 n ((<= 0) . (xs VU.!))+-- Nothing+--+-- >>> bisectL 0 n ((<= 100) . (xs VU.!))+-- Just 5+--+-- >>> bisectL 0 3 ((<= 20) . (xs VU.!))+-- Just 2+--+-- @since 1.1.0.0+{-# INLINE bisectL #-}+bisectL :: (HasCallStack) => Int -> Int -> (Int -> Bool) -> Maybe Int+bisectL l r p = runIdentity $ bisectLM l r (pure . p)++-- | \(O(\log n)\) Monadic variant of `bisectL`.+--+-- @since 1.1.0.0+{-# INLINE bisectLM #-}+bisectLM :: (HasCallStack, Monad m) => Int -> Int -> (Int -> m Bool) -> m (Maybe Int)+bisectLM l r p+ | l >= r = pure Nothing+ | otherwise =+ bisectLImpl p l r <&> \case+ i | i == (l - 1) -> Nothing+ i -> Just i++-- | \(O(\log n)\) Applies the bisection method on a half-open interval \([l, r)\) and returns the+-- right boundary point, or `Nothing` if no such point exists.+--+--+-- @+-- Y Y Y Y Y N N N N N Y: user predicate holds+-- --------- *---------> X N: user predicate does not hold+-- R R: the right boundary point returned+-- @+--+-- ==== __Example__+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let xs = VU.fromList [10, 10, 20, 20, 30, 30]+-- >>> let n = VU.length xs+-- >>> bisectR 0 n ((<= 20) . (xs VU.!))+-- Just 4+--+-- >>> bisectR 0 n ((<= 0) . (xs VU.!))+-- Just 0+--+-- >>> bisectR 0 n ((<= 100) . (xs VU.!))+-- Nothing+--+-- >>> bisectR 0 4 ((<= 20) . (xs VU.!))+-- Nothing+--+-- @since 1.1.0.0+{-# INLINE bisectR #-}+bisectR :: (HasCallStack) => Int -> Int -> (Int -> Bool) -> Maybe Int+bisectR l r p = runIdentity $ bisectRM l r (pure . p)++-- | \(O(\log n)\) Monadic variant of `bisectR`.+--+-- @since 1.1.0.0+{-# INLINE bisectRM #-}+bisectRM :: (HasCallStack, Monad m) => Int -> Int -> (Int -> m Bool) -> m (Maybe Int)+bisectRM l r p+ | l >= r = pure Nothing+ | otherwise =+ bisectRImpl p l r <&> \case+ i | i == r -> Nothing+ i -> Just i
+ src/AtCoder/Extra/Graph.hs view
@@ -0,0 +1,147 @@+-- | Re-export of the @Csr@ module and generic graph search functions.+--+-- @since 1.1.0.0+module AtCoder.Extra.Graph+ ( -- * Re-export of CSR++ -- | The `Csr.Csr` data type and all the functions such as `build` or `adj` are re-exported.+ module Csr,++ -- * CSR helpers+ swapDupe,+ swapDupe',+ scc,++ -- * Graph search+ topSort,+ )+where++import AtCoder.Extra.IntSet qualified as IS+import AtCoder.Internal.Buffer qualified as B+import AtCoder.Internal.Csr as Csr+import AtCoder.Internal.Scc qualified as ACISCC+import Control.Monad (when)+import Control.Monad.ST (runST)+import Data.Foldable (for_)+import Data.Vector qualified as V+import Data.Vector.Generic.Mutable qualified as VGM+import Data.Vector.Unboxed qualified as VU+import Data.Vector.Unboxed.Mutable qualified as VUM++-- | \(O(n)\) Converts non-directed edges into directional edges. This is a convenient function for+-- making an input to `build`.+--+-- ==== __Example__+-- `swapDupe` duplicates each edge reversing the direction:+--+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> Gr.swapDupe $ VU.fromList [(0, 1, ()), (1, 2, ())]+-- [(0,1,()),(1,0,()),(1,2,()),(2,1,())]+--+-- Create a non-directed graph:+--+-- >>> let gr = Gr.build 3 . Gr.swapDupe $ VU.fromList [(0, 1, ()), (1, 2, ())]+-- >>> gr `Gr.adj` 0+-- [1]+--+-- >>> gr `Gr.adj` 1+-- [0,2]+--+-- >>> gr `Gr.adj` 2+-- [1]+--+-- @since 1.1.0.0+{-# INLINE swapDupe #-}+swapDupe :: (VU.Unbox (Int, Int, w)) => VU.Vector (Int, Int, w) -> VU.Vector (Int, Int, w)+swapDupe = VU.concatMap (\(!u, !v, !w) -> VU.fromListN 2 [(u, v, w), (v, u, w)])++-- | \(O(n)\) Converts non-directed edges into directional edges. This is a convenient function for+-- making an input to `build'`.+--+-- ==== __Example__+-- `swapDupe'` duplicates each edge reversing the direction:+--+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> Gr.swapDupe' $ VU.fromList [(0, 1), (1, 2)]+-- [(0,1),(1,0),(1,2),(2,1)]+--+-- Create a non-directed graph:+--+-- >>> let gr = Gr.build' 3 . Gr.swapDupe' $ VU.fromList [(0, 1), (1, 2)]+-- >>> gr `Gr.adj` 0+-- [1]+--+-- >>> gr `Gr.adj` 1+-- [0,2]+--+-- >>> gr `Gr.adj` 2+-- [1]+--+-- @since 1.1.0.0+{-# INLINE swapDupe' #-}+swapDupe' :: (VU.Unbox (Int, Int)) => VU.Vector (Int, Int) -> VU.Vector (Int, Int)+swapDupe' = VU.concatMap (\(!u, !v) -> VU.fromListN 2 [(u, v), (v, u)])++-- | \(O(n + m)\) Returns the strongly connected components.+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> -- 0 == 1 -> 2 3+-- >>> let gr = Gr.build' 4 $ VU.fromList [(0, 1), (1, 0), (1, 2)]+-- >>> Gr.scc gr+-- [[3],[0,1],[2]]+--+-- @since 1.1.0.0+{-# INLINE scc #-}+scc :: Csr w -> V.Vector (VU.Vector Int)+scc = ACISCC.sccCsr++-- | \(O(n \log n + m)\) Returns the lexicographically smallest topological ordering of the given+-- graph.+--+-- ==== Constraints+-- - The graph must be a DAG.+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let n = 5+-- >>> let gr = Gr.build' n $ VU.fromList [(1, 2), (4, 0), (0, 3)]+-- >>> Gr.topSort n (gr `Gr.adj`)+-- [1,2,4,0,3]+--+-- @since 1.1.0.0+{-# INLINE topSort #-}+topSort :: Int -> (Int -> VU.Vector Int) -> VU.Vector Int+topSort n gr = runST $ do+ inDeg <- VUM.replicate n (0 :: Int)+ for_ [0 .. n - 1] $ \u -> do+ VU.forM_ (gr u) $ \v -> do+ VGM.modify inDeg (+ 1) v++ -- start from the vertices with zero in-degrees:+ que <- IS.new n+ inDeg' <- VU.unsafeFreeze inDeg+ VU.iforM_ inDeg' $ \v d -> do+ when (d == 0) $ do+ IS.insert que v++ buf <- B.new n+ let run = do+ IS.deleteMin que >>= \case+ Nothing -> pure ()+ Just u -> do+ B.pushBack buf u+ VU.forM_ (gr u) $ \v -> do+ nv <- subtract 1 <$> VGM.read inDeg v+ VGM.write inDeg v nv+ when (nv == 0) $ do+ IS.insert que v+ run++ run+ B.unsafeFreeze buf
+ src/AtCoder/Extra/HashMap.hs view
@@ -0,0 +1,346 @@+{-# LANGUAGE RecordWildCards #-}++-- original implementaion:+-- <https://github.com/maspypy/library/blob/main/ds/hashmap.hpp>++-- | A dense, fast `Int` hash map with a fixed-sized `capacity` of \(n\). Most operations are+-- performed in \(O(1)\) time, but in average.+--+-- NOTE: The entries (key - value pairs) cannot be invalidated due to the internal implementation+-- (called /open addressing/).+--+-- ==== __Example__+-- Create a `HashMap` with `capacity` \(10\):+--+-- >>> import AtCoder.Extra.HashMap qualified as HM+-- >>> hm <- HM.new @_ @Int 10+--+-- `insert`, `lookup` and other functions are available in \(O(1)\) averaged time:+--+-- >>> HM.insert hm 0 100+-- >>> HM.insert hm 10 101+-- >>> HM.size hm+-- 2+--+-- >>> HM.lookup hm 0+-- Just 100+--+-- >>> HM.lookup hm 10+-- Just 101+--+-- @since 1.1.0.0+module AtCoder.Extra.HashMap+ ( -- * HashMap+ HashMap,++ -- * Constructors+ new,+ build,++ -- * Metadata+ capacity,+ size,++ -- * Lookups+ lookup,+ member,+ notMember,++ -- * Modifications++ -- ** Insertions+ insert,+ insertWith,+ exchange,++ -- ** Updates+ modify,+ modifyM,++ -- ** Reset+ clear,++ -- * Conversions++ -- ** Safe conversions+ keys,+ elems,+ assocs,++ -- ** Unsafe conversions+ unsafeKeys,+ unsafeElems,+ unsafeAssocs,+ )+where++import AtCoder.Internal.Assert qualified as ACIA+import Control.Monad (void, when)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Bit (Bit (..))+import Data.Bits (Bits (xor, (.&.)), (.>>.))+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 Data.Word (Word64)+import GHC.Stack (HasCallStack)+import Prelude hiding (lookup)++-- | A dense, fast `Int` hash map with a fixed-sized capacity of \(n\).+--+-- @since 1.1.0.0+data HashMap s a = HashMap+ { -- | Maximum number of elements.+ maxCapHM :: {-# UNPACK #-} !Int,+ -- | The number of elements that can be added.+ restCapHM :: !(VUM.MVector s Int),+ -- | Bit mask for powerset iteration on indexing.+ maskHM :: {-# UNPACK #-} !Int,+ -- | Original key to the hash index.+ keyHM :: !(VUM.MVector s Int),+ -- | Values to the hash index.+ valHM :: !(VUM.MVector s a),+ -- | Whether the slot is used or not.+ usedHM :: !(VUM.MVector s Bit)+ }++{-# INLINE decrementRestCapacity #-}+decrementRestCapacity :: (HasCallStack, PrimMonad m) => VUM.MVector (PrimState m) Int -> String -> m ()+decrementRestCapacity restCap funcName = do+ rest <- VGM.unsafeRead restCap 0+ let !_ = ACIA.runtimeAssert (rest > 0) $ "AtCoder.Extra.HashMap." ++ funcName ++ ": out of capacity"+ VGM.unsafeWrite restCap 0 (rest - 1)+ pure ()++-- | \(O(n)\) Creates a `HashMap` of capacity \(n\).+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (PrimMonad m, VU.Unbox a) => Int -> m (HashMap (PrimState m) a)+new n = do+ let !k0 = 1+ let !k = until (>= 2 * n) (* 2) k0+ let !maxCapHM = k `div` 2+ restCapHM <- VUM.replicate 1 maxCapHM+ let !maskHM = k - 1+ keyHM <- VUM.unsafeNew k+ valHM <- VUM.unsafeNew k+ usedHM <- VUM.replicate k $ Bit False+ pure HashMap {..}++-- | \(O(n)\) Creates a `HashMap` of capacity \(n\) with initial entries.+--+-- @since 1.1.0.0+{-# INLINE build #-}+build :: (PrimMonad m, VU.Unbox a) => Int -> VU.Vector (Int, a) -> m (HashMap (PrimState m) a)+build n xs = do+ hm <- new n+ VU.forM_ xs $ \(!i, !x) -> do+ insert hm i x+ pure hm++-- | \(O(1)\) Returns the maximum number of elements the hash map can store.+--+-- @since 1.1.0.0+{-# INLINE capacity #-}+capacity :: HashMap s a -> Int+capacity = maxCapHM++-- | \(O(1)\) Returns the number of elements in the hash map.+--+-- @since 1.1.0.0+{-# INLINE size #-}+size :: (PrimMonad m) => HashMap (PrimState m) a -> m Int+size HashMap {..} = do+ !rest <- VUM.unsafeRead restCapHM 0+ pure $ maxCapHM - rest++-- | \(O(1)\) (Internal) Hash value calculation.+--+-- @since 1.1.0.0+{-# INLINE hash #-}+hash :: HashMap a s -> Int -> Int+hash hm x = fromIntegral $ (x3 `xor` (x3 .>>. 31)) .&. fromIntegral (maskHM hm)+ where+ fixedRandom, x1, x2, x3 :: Word64+ fixedRandom = 321896566547+ x1 = fromIntegral x + fixedRandom+ x2 = (x1 `xor` (x1 .>>. 30)) * 0xbf58476d1ce4e5b9+ x3 = (x2 `xor` (x2 .>>. 27)) * 0x94d049bb133111eb++-- | \(O(1)\) (Internal) Hashed slot search.+--+-- @since 1.1.0.0+{-# INLINE index #-}+index :: (PrimMonad m) => HashMap (PrimState m) a -> Int -> m Int+index hm@HashMap {..} k = inner (hash hm k)+ where+ inner !h = do+ Bit b <- VGM.read usedHM h+ -- already there?+ k' <- VGM.read keyHM h+ if b && k' /= k+ then inner $ (h + 1) .&. maskHM+ else pure h++-- | \(O(1)\) Return the value to which the specified key is mapped, or `Nothing` if this map+-- contains no mapping for the key.+--+-- @since 1.1.0.0+{-# INLINE lookup #-}+lookup :: (HasCallStack, VU.Unbox a, PrimMonad m) => HashMap (PrimState m) a -> Int -> m (Maybe a)+lookup hm@HashMap {..} k = do+ i <- index hm k+ Bit b <- VGM.read usedHM i+ if b+ then Just <$> VGM.read valHM i+ else pure Nothing++-- | \(O(1)\) Checks whether the hash map contains the element.+--+-- @since 1.1.0.0+{-# INLINE member #-}+member :: (HasCallStack, PrimMonad m) => HashMap (PrimState m) a -> Int -> m Bool+member hm@HashMap {..} k = do+ i <- index hm k+ Bit b <- VGM.read usedHM i+ -- TODO: is this key check necessary+ k' <- VGM.read keyHM i+ pure $ b && k' == k++-- | \(O(1)\) Checks whether the hash map does not contain the element.+--+-- @since 1.1.0.0+{-# INLINE notMember #-}+notMember :: (HasCallStack, PrimMonad m) => HashMap (PrimState m) a -> Int -> m Bool+notMember hm k = not <$> member hm k++-- | \(O(1)\) Inserts a \((k, v)\) pair.+--+-- @since 1.1.0.0+{-# INLINE insert #-}+insert :: (HasCallStack, PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> Int -> a -> m ()+insert hm k v = void $ exchange hm k v++-- | \(O(1)\) Inserts a \((k, v)\) pair. If the key exists, the function will insert the pair+-- \((k, f(v_{\mathrm{new}}, v_{\mathrm{old}}))\).+--+-- @since 1.1.0.0+{-# INLINE insertWith #-}+insertWith :: (HasCallStack, PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> (a -> a -> a) -> Int -> a -> m ()+insertWith hm@HashMap {..} f k v = do+ i <- index hm k+ Bit b <- VGM.exchange usedHM i $ Bit True+ if b+ then do+ -- modify the existing entry+ VGM.modify valHM (f v) i+ else do+ -- insert the new \((k, v)\) pair+ decrementRestCapacity restCapHM "insertWith"+ VGM.write keyHM i k+ VGM.write valHM i v++-- | \(O(1)\) Inserts a \((k, v)\) pair and returns the old value, or `Nothing` if no such entry+-- exists.+--+-- @since 1.1.0.0+{-# INLINE exchange #-}+exchange :: (HasCallStack, PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> Int -> a -> m (Maybe a)+exchange hm@HashMap {..} k v = do+ i <- index hm k+ Bit b <- VGM.exchange usedHM i $ Bit True+ if b+ then do+ -- overwrite the existing entry+ Just <$> VGM.exchange valHM i v+ else do+ -- insert the new (key, value) pair+ decrementRestCapacity restCapHM "exchange"+ VGM.write keyHM i k+ VGM.write valHM i v+ pure Nothing++-- | \(O(1)\) Modifies the element at the given key. Does nothing if no such entry exists.+--+-- @since 1.1.0.0+{-# INLINE modify #-}+modify :: (HasCallStack, PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> (a -> a) -> Int -> m ()+modify hm@HashMap {..} f k = do+ i <- index hm k+ Bit b <- VGM.read usedHM i+ when b $ do+ VGM.modify valHM f i++-- | \(O(1)\) Modifies the element at the given key. Does nothing if no such entry exists.+--+-- @since 1.1.0.0+{-# INLINE modifyM #-}+modifyM :: (HasCallStack, PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> (a -> m a) -> Int -> m ()+modifyM hm@HashMap {..} f k = do+ i <- index hm k+ Bit b <- VGM.read usedHM i+ when b $ do+ VGM.modifyM valHM f i++-- | \(O(n)\) Clears all the elements.+--+-- @since 1.1.0.0+{-# INLINE clear #-}+clear :: (PrimMonad m) => HashMap (PrimState m) a -> m ()+clear HashMap {..} = do+ VGM.set usedHM $ Bit False+ VUM.unsafeWrite restCapHM 0 maxCapHM++-- | \(O(n)\) Enumerates the keys in the hash map.+--+-- @since 1.1.0.0+{-# INLINE keys #-}+keys :: (PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> m (VU.Vector Int)+keys hm = VU.force <$> unsafeKeys hm++-- | \(O(n)\) Enumerates the elements (values) in the hash map.+--+-- @since 1.1.0.0+{-# INLINE elems #-}+elems :: (PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> m (VU.Vector a)+elems hm = VU.force <$> unsafeElems hm++-- | \(O(n)\) Enumerates the key-value pairs in the hash map.+--+-- @since 1.1.0.0+{-# INLINE assocs #-}+assocs :: (PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> m (VU.Vector (Int, a))+assocs hm = VU.force <$> unsafeAssocs hm++-- | \(O(n)\) Enumerates the keys in the hash map.+--+-- @since 1.1.0.0+{-# INLINE unsafeKeys #-}+unsafeKeys :: (PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> m (VU.Vector Int)+unsafeKeys HashMap {..} = do+ used <- VU.unsafeFreeze usedHM+ keys_ <- VU.unsafeFreeze keyHM+ pure $ VU.ifilter (const . unBit . (used VG.!)) keys_++-- | \(O(n)\) Enumerates the elements (values) in the hash map.+--+-- @since 1.1.0.0+{-# INLINE unsafeElems #-}+unsafeElems :: (PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> m (VU.Vector a)+unsafeElems HashMap {..} = do+ used <- VU.unsafeFreeze usedHM+ vals <- VU.unsafeFreeze valHM+ pure $ VU.ifilter (const . unBit . (used VG.!)) vals++-- | \(O(n)\) Enumerates the key-value pairs in the hash map.+--+-- @since 1.1.0.0+{-# INLINE unsafeAssocs #-}+unsafeAssocs :: (PrimMonad m, VU.Unbox a) => HashMap (PrimState m) a -> m (VU.Vector (Int, a))+unsafeAssocs HashMap {..} = do+ used <- VU.unsafeFreeze usedHM+ keys_ <- VU.unsafeFreeze keyHM+ vals <- VU.unsafeFreeze valHM+ pure $ VU.ifilter (const . unBit . (used VG.!)) $ VU.zip keys_ vals
+ src/AtCoder/Extra/IntMap.hs view
@@ -0,0 +1,338 @@+{-# LANGUAGE RecordWildCards #-}++-- | A dense, fast `Int` map implemented as a 64-ary tree that covers an interval \([0, n)\).+--+-- ==== __Example__+-- Create an `IntMap` with capacity \(10\):+--+-- >>> import AtCoder.Extra.IntMap qualified as IM+-- >>> im <- IM.new @_ @Int 10+--+-- `insert`, `delete`, `lookup` and other functions are available:+--+-- >>> IM.insert im 0 100+-- >>> IM.insert im 9 101+-- >>> IM.delete im 0+-- True+--+-- >>> IM.size im+-- 1+--+-- >>> IM.lookup im 9+-- Just 101+--+-- >>> IM.lookup im 1+-- Nothing+--+-- >>> IM.lookupGT im 5+-- Just (9,101)+--+-- @since 1.1.0.0+module AtCoder.Extra.IntMap+ ( -- * IntMap+ IntMap,++ -- * Constructors+ new,+ build,++ -- * Metadata+ capacity,+ size,+ null,++ -- * Lookups+ lookup,+ member,+ notMember,++ -- ** Compartive lookups+ lookupGE,+ lookupGT,+ lookupLE,+ lookupLT,++ -- ** Max/Min lookups+ lookupMin,+ lookupMax,++ -- * Modifications++ -- ** Insertions+ insert,+ insertWith,++ -- ** Updates+ modify,+ modifyM,++ -- ** Deletions+ delete,+ delete_,+ deleteMin,+ deleteMax,++ -- * Conversions+ keys,+ elems,+ assocs,+ )+where++import AtCoder.Extra.IntSet qualified as IS+import Control.Monad (when)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Maybe (fromJust)+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 (lookup, null)++-- | A dense, fast `Int` map implemented as a 64-ary tree that covers an interval \([0, n)\).+--+-- @since 1.1.0.0+data IntMap s a = IntMap+ { setIM :: !(IS.IntSet s),+ valIM :: !(VUM.MVector s a)+ }++-- | \(O(n)\) Creates an `IntMap` for an interval \([0, n)\).+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (PrimMonad m, VU.Unbox a) => Int -> m (IntMap (PrimState m) a)+new cap = do+ setIM <- IS.new cap+ valIM <- VUM.unsafeNew cap+ pure IntMap {..}++-- | \(O(n + m \log n)\) Creates an `IntMap` for an interval \([0, n)\) with initial values.+--+-- @since 1.1.0.0+{-# INLINE build #-}+build :: (PrimMonad m, VU.Unbox a) => Int -> VU.Vector (Int, a) -> m (IntMap (PrimState m) a)+build cap xs = do+ im <- new cap+ VU.forM_ xs $ \(!k, !v) -> do+ insert im k v+ pure im++-- | \(O(1)\) Returns the capacity \(n\), where the interval \([0, n)\) is covered by the map.+--+-- @since 1.1.0.0+{-# INLINE capacity #-}+capacity :: IntMap s a -> Int+capacity = IS.capacity . setIM++-- | \(O(1)\) Returns the number of elements in the map.+--+-- @since 1.1.0.0+{-# INLINE size #-}+size :: (PrimMonad m) => IntMap (PrimState m) a -> m Int+size = IS.size . setIM++-- | \(O(1)\) Returns whether the map is empty.+--+-- @since 1.1.0.0+{-# INLINE null #-}+null :: (PrimMonad m) => IntMap (PrimState m) a -> m Bool+null = IS.null . setIM++-- | \(O(\log n)\) Looks up the value for a key.+--+-- @since 1.1.0.0+{-# INLINE lookup #-}+lookup :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe a)+lookup im@IntMap {..} k = do+ member im k >>= \case+ True -> Just <$> VGM.read valIM k+ False -> pure Nothing++-- | \(O(\log n)\) Tests whether a key \(k\) is in the map.+--+-- @since 1.1.0.0+{-# INLINE member #-}+member :: (PrimMonad m) => IntMap (PrimState m) a -> Int -> m Bool+member = IS.member . setIM++-- | \(O(\log n)\) Tests whether a key \(k\) is not in the map.+--+-- @since 1.1.0.0+{-# INLINE notMember #-}+notMember :: (PrimMonad m) => IntMap (PrimState m) a -> Int -> m Bool+notMember = IS.notMember . setIM++-- | \(O(\log n)\) Looks up the \((k, v)\) pair with the smallest key \(k\) such that \(k \ge k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupGE #-}+lookupGE :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))+lookupGE IntMap {..} k = do+ IS.lookupGE setIM k >>= \case+ Just i -> Just . (i,) <$> VGM.read valIM i+ Nothing -> pure Nothing++-- | \(O(\log n)\) Looks up the \((k, v)\) pair with the smallest \(k\) such that \(k \gt k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupGT #-}+lookupGT :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))+lookupGT is k = lookupGE is (k + 1)++-- | \(O(\log n)\) Looks up the \((k, v)\) pair with the largest key \(k\) such that \(k \le k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupLE #-}+lookupLE :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))+lookupLE IntMap {..} k = do+ IS.lookupLE setIM k >>= \case+ Just i -> Just . (i,) <$> VGM.read valIM i+ Nothing -> pure Nothing++-- | \(O(\log n)\) Looks up the \((k, v)\) pair with the largest key \(k\) such that \(k \lt k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupLT #-}+lookupLT :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> Int -> m (Maybe (Int, a))+lookupLT is k = lookupLE is (k - 1)++-- | \(O(\log n)\) Looks up the \((k, v)\) pair with the minimum key \(k\).+--+-- @since 1.1.0.0+{-# INLINE lookupMin #-}+lookupMin :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))+lookupMin is = lookupGE is 0++-- | \(O(\log n)\) Looks up the \((k, v)\) pair with the maximum key \(k\).+--+-- @since 1.1.0.0+{-# INLINE lookupMax #-}+lookupMax :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))+lookupMax im = lookupLE im (IS.capacity (setIM im) - 1)++-- | \(O(\log n)\) Inserts a \((k, v)\) pair into the map. If an entry with the same key already+-- exists, it is overwritten.+--+-- @since 1.1.0.0+{-# INLINE insert #-}+insert :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> Int -> a -> m ()+insert IntMap {..} k v = do+ IS.insert setIM k+ VGM.write valIM k v++-- | \(O(\log n)\) Inserts a \((k, v)\) pair into the map. If an entry with the same key already+-- exists, it overwritten with \(f(v_{\mathrm{new}}, v_{\mathrm{old}})\).+--+-- @since 1.1.0.0+{-# INLINE insertWith #-}+insertWith :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> (a -> a -> a) -> Int -> a -> m ()+insertWith IntMap {..} f k v = do+ b <- IS.member setIM k+ if b+ then do+ VGM.modify valIM (f v) k+ else do+ IS.insert setIM k+ VGM.write valIM k v++-- | \(O(\log n)\) Modifies the value associated with a key. If an entry with the same key already+-- does not exist, nothing is performed.+--+-- @since 1.1.0.0+{-# INLINE modify #-}+modify :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> (a -> a) -> Int -> m ()+modify IntMap {..} f k = do+ b <- IS.member setIM k+ when b $ do+ VGM.modify valIM f k++-- | \(O(\log n)\) Modifies the value associated with a key. If an entry with the same key already+-- does not exist, nothing is performed.+--+-- @since 1.1.0.0+{-# INLINE modifyM #-}+modifyM :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> (a -> m a) -> Int -> m ()+modifyM IntMap {..} f k = do+ b <- IS.member setIM k+ when b $ do+ VGM.modifyM valIM f k++-- | \(O(\log n)\) Deletes the \((k, v)\) pair with the key \(k\) from the map. Does nothing if no+-- such key exists. Returns whether the key existed.+--+-- @since 1.1.0.0+{-# INLINE delete #-}+delete :: (PrimMonad m) => IntMap (PrimState m) a -> Int -> m Bool+delete im = IS.delete (setIM im)++-- | \(O(\log n)\) Deletes the \((k, v)\) pair with the key \(k\) from the map. Does nothing if no+-- such key exists.+--+-- @since 1.1.0.0+{-# INLINE delete_ #-}+delete_ :: (PrimMonad m) => IntMap (PrimState m) a -> Int -> m ()+delete_ im = IS.delete_ (setIM im)++-- | \(O(\log n)\) Deletes the \((k, v)\) pair with the minimum key \(k\) in the map.+--+-- @since 1.1.0.0+{-# INLINE deleteMin #-}+deleteMin :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))+deleteMin is = do+ lookupMin is+ >>= mapM+ ( \(!key, !val) -> do+ delete_ is key+ pure (key, val)+ )++-- | \(O(\log n)\) Deletes the \((k, v)\) pair with maximum key \(k\) in the map.+--+-- @since 1.1.0.0+{-# INLINE deleteMax #-}+deleteMax :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> m (Maybe (Int, a))+deleteMax is = do+ lookupMax is+ >>= mapM+ ( \(!k, !v) -> do+ delete_ is k+ pure (k, v)+ )++-- | \(O(n \log n)\) Enumerates the keys in the map.+--+-- @since 1.1.0.0+{-# INLINE keys #-}+keys :: (PrimMonad m) => IntMap (PrimState m) a -> m (VU.Vector Int)+keys = IS.keys . setIM++-- | \(O(n \log n)\) Enumerates the elements (values) in the map.+--+-- @since 1.1.0.0+{-# INLINE elems #-}+elems :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> m (VU.Vector a)+elems im@IntMap {..} = do+ n <- IS.size setIM+ VU.unfoldrExactNM+ n+ ( \i -> do+ (!i', !x') <- fromJust <$> lookupGT im i+ pure (x', i')+ )+ (-1)++-- | \(O(n \log n)\) Enumerates the key-value pairs in the map.+--+-- @since 1.1.0.0+{-# INLINE assocs #-}+assocs :: (PrimMonad m, VU.Unbox a) => IntMap (PrimState m) a -> m (VU.Vector (Int, a))+assocs im@IntMap {..} = do+ n <- IS.size setIM+ VU.unfoldrExactNM+ n+ ( \i -> do+ (!i', !x') <- fromJust <$> lookupGT im i+ pure ((i', x'), i')+ )+ (-1)
+ src/AtCoder/Extra/IntSet.hs view
@@ -0,0 +1,391 @@+{-# LANGUAGE RecordWildCards #-}++-- original implementation:+-- <https://github.com/maspypy/library/blob/main/ds/fastset.hpp>++-- | A dense, fast `Int` set implemented as a 64-ary tree that covers an interval \([0, n)\).+--+-- ==== __Example__+-- Create an `IntSet` with capacity \(10\):+--+-- >>> import AtCoder.Extra.IntSet qualified as IS+-- >>> is <- IS.new @_ 10+--+-- `insert`, `delete` and other functions are available:+--+-- >>> IS.insert is 0+-- >>> IS.insert is 9+-- >>> IS.member is 9+-- True+--+-- >>> IS.delete is 0+-- True+--+-- >>> IS.size is+-- 1+--+-- >>> IS.member is 1+-- False+--+-- >>> IS.lookupGT is 5+-- Just 9+--+-- @since 1.1.0.0+module AtCoder.Extra.IntSet+ ( -- * IntSet+ IntSet,++ -- * Constructors+ new,+ build,++ -- * Metadata+ capacity,+ size,+ null,++ -- * Lookups+ member,+ notMember,++ -- ** Compartive lookups+ lookupGE,+ lookupGT,+ lookupLE,+ lookupLT,++ -- ** Max/Min lookups+ lookupMin,+ lookupMax,++ -- * Modifications++ -- ** Insertions+ insert,++ -- ** Deletions+ delete,+ delete_,+ deleteMin,+ deleteMax,++ -- * Conversions+ keys,+ )+where++import AtCoder.Internal.Assert qualified as ACIA+import Control.Monad (unless, void)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Bifunctor (bimap)+import Data.Bits+ ( Bits (clearBit, setBit, testBit),+ FiniteBits (countLeadingZeros, countTrailingZeros),+ (.<<.),+ (.>>.),+ )+import Data.Maybe (fromJust)+import Data.Vector qualified as V+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 (null)++-- | \(O(1)\) Retrieves the most significant bit.+--+-- >>> msbOf 0+-- -1+--+-- >>> msbOf maxBound+-- 62+--+-- >>> msbOf $ 4 + 2 + 1+-- 2+{-# INLINE msbOf #-}+msbOf :: Int -> Int+msbOf !x = 63 - countLeadingZeros x++-- | \(O(1)\) Retrieves the least significant bit.+--+-- >>> lsbOf 0+-- -1+--+-- >>> lsbOf maxBound+-- 0+--+-- >>> lsbOf $ 4 + 2 + 1+-- 0+{-# INLINE lsbOf #-}+lsbOf :: Int -> Int+lsbOf 0 = -1+lsbOf x = countTrailingZeros x++{-# INLINE wordSize #-}+wordSize :: Int+wordSize = 64++-- | A dense, fast `Int` set implemented as a 64-ary tree that covers an interval \([0, n)\).+--+-- @since 1.1.0.0+data IntSet s = IntSet+ { -- | Maximum number of elements.+ capacityIS :: {-# UNPACK #-} !Int,+ -- | The number of elements.+ sizeIS :: !(VUM.MVector s Int),+ -- | Segments.+ vecIS :: !(V.Vector (VUM.MVector s Int))+ }++-- | \(O(n)\) Creates an `IntSet` for the interval \([0, n)\).+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (PrimMonad m) => Int -> m (IntSet (PrimState m))+new capacityIS = do+ vecIS <-+ V.unfoldrExactNM+ (max 1 logSize)+ ( \len -> do+ let !len' = (len + wordSize - 1) `div` wordSize+ (,len') <$> VUM.replicate len' 0+ )+ capacityIS+ sizeIS <- VUM.replicate 1 (0 :: Int)+ pure IntSet {..}+ where+ (!_, !logSize) =+ until+ ((<= 1) . fst)+ (bimap ((`div` wordSize) . (+ (wordSize - 1))) (+ 1))+ (capacityIS, 0)++-- | \(O(n + m \log n)\) Creates an `IntSet` for the interval \([0, n)\) with initial values.+--+-- @since 1.1.0.0+{-# INLINE build #-}+build :: (PrimMonad m) => Int -> VU.Vector Int -> m (IntSet (PrimState m))+build n vs = do+ set <- new n+ VU.forM_ vs (insert set)+ pure set++-- | \(O(1)\) Returns the capacity \(n\), where the interval \([0, n)\) is covered by the set.+--+-- @since 1.1.0.0+{-# INLINE capacity #-}+capacity :: IntSet s -> Int+capacity = capacityIS++-- | \(O(1)\) Returns the number of elements in the set.+--+-- @since 1.1.0.0+{-# INLINE size #-}+size :: (PrimMonad m) => IntSet (PrimState m) -> m Int+size = (`VUM.unsafeRead` 0) . sizeIS++-- | \(O(1)\) Returns whether the set is empty.+--+-- @since 1.1.0.0+{-# INLINE null #-}+null :: (PrimMonad m) => IntSet (PrimState m) -> m Bool+null = ((== 0) <$>) . size++-- | \(O(\log n)\) Tests whether \(k\) is in the set.+--+-- @since 1.1.0.0+{-# INLINE member #-}+member :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m Bool+member IntSet {..} k+ | ACIA.testIndex k capacityIS = do+ let (!q, !r) = k `divMod` wordSize+ (`testBit` r) <$> VGM.unsafeRead (VG.unsafeHead vecIS) q+ | otherwise = pure False++-- | \(O(\log n)\) Tests whether \(k\) is not in the set.+--+-- @since 1.1.0.0+{-# INLINE notMember #-}+notMember :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m Bool+notMember dis k = not <$> member dis k++-- | \(O(\log n)\) Looks up the smallest key \(k\) such that \(k \ge k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupGE #-}+lookupGE :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m (Maybe Int)+lookupGE IntSet {..} i0+ | i0 >= capacityIS = pure Nothing+ | otherwise = inner 0 $ max 0 i0 -- REMARK: it's very important to keep @i@ non-negative.+ where+ inner h i+ | h >= V.length vecIS = pure Nothing+ -- ?+ | q == VUM.length (VG.unsafeIndex vecIS h) = pure Nothing+ | otherwise = do+ d <- (.>>. r) <$> VGM.unsafeRead (VG.unsafeIndex vecIS h) q+ if d == 0+ then inner (h + 1) (q + 1)+ else+ Just+ <$> V.foldM'+ ( \ !acc vec -> do+ !dx <- lsbOf <$> VGM.unsafeRead vec acc+ pure $ acc * wordSize + dx+ )+ (i + lsbOf d)+ (V.unsafeBackpermute vecIS (V.enumFromStepN (h - 1) (-1) h))+ where+ (!q, !r) = i `divMod` wordSize++-- | \(O(\log n)\) Looks up the smallest key \(k\) such that \(k \gt k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupGT #-}+lookupGT :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m (Maybe Int)+lookupGT is k = lookupGE is (k + 1)++-- | \(O(\log n)\) Looks up the largest key \(k\) such that \(k \le k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupLE #-}+lookupLE :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m (Maybe Int)+lookupLE IntSet {..} i0+ | i0 <= -1 = pure Nothing+ | otherwise = inner 0 $ min (capacityIS - 1) i0+ where+ inner h i+ | h >= V.length vecIS = pure Nothing+ | i == -1 = pure Nothing+ | otherwise = do+ d <- (.<<. (63 - r)) <$> VGM.unsafeRead (VG.unsafeIndex vecIS h) q+ if d == 0+ then inner (h + 1) (q - 1)+ else do+ Just+ <$> V.foldM'+ ( \ !acc vec -> do+ !dx <- msbOf <$> VGM.unsafeRead vec acc+ pure $ acc * wordSize + dx+ )+ (i - countLeadingZeros d)+ (V.unsafeBackpermute vecIS (V.enumFromStepN (h - 1) (-1) h))+ where+ (!q, !r) = i `divMod` wordSize++-- | \(O(\log n)\) Looks up the largest key \(k\) such that \(k \lt k_0\).+--+-- @since 1.1.0.0+{-# INLINE lookupLT #-}+lookupLT :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m (Maybe Int)+lookupLT is k = lookupLE is (k - 1)++-- | \(O(\log n)\) Looks up the minimum key.+--+-- @since 1.1.0.0+{-# INLINE lookupMin #-}+lookupMin :: (PrimMonad m) => IntSet (PrimState m) -> m (Maybe Int)+lookupMin is = lookupGE is 0++-- | \(O(\log n)\) Looks up the maximum key.+--+-- @since 1.1.0.0+{-# INLINE lookupMax #-}+lookupMax :: (PrimMonad m) => IntSet (PrimState m) -> m (Maybe Int)+lookupMax is = lookupLE is (capacityIS is - 1)++-- | \(O(\log n)\) Inserts a key \(k\) into the set. If an entry with the same key already exists,+-- it is overwritten.+--+-- @since 1.1.0.0+{-# INLINE insert #-}+insert :: (HasCallStack, PrimMonad m) => IntSet (PrimState m) -> Int -> m ()+insert is@IntSet {..} k = do+ b <- member is k+ unless b $ do+ VUM.unsafeModify sizeIS (+ 1) 0+ V.foldM'_+ ( \i vec -> do+ let (!q, !r) = i `divMod` wordSize+ VGM.unsafeModify vec (`setBit` r) q+ pure q+ )+ k+ vecIS+ where+ !_ = ACIA.checkIndex "AtCoder.Extra.IntSet.insert" k capacityIS++-- | \(O(\log n)\) Deletes a key \(k\) from the set. Does nothing if no such key exists. Returns+-- whether the key existed.+--+-- @since 1.1.0.0+{-# INLINE delete #-}+delete :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m Bool+delete is@IntSet {..} k = do+ b_ <- member is k+ if b_+ then do+ VUM.unsafeModify sizeIS (subtract 1) 0+ V.foldM'_+ ( \(!b, !i) vec -> do+ let (!q, !r) = i `divMod` wordSize+ -- TODO: early return is possible+ unless b $ do+ VGM.unsafeModify vec (`clearBit` r) q+ -- `b` remembers if any other bit was on+ b' <- (/= 0) <$> VGM.unsafeRead vec q+ pure (b', q)+ )+ (False, k)+ vecIS+ pure True+ else pure False++-- | \(O(\log n)\) Deletes a key \(k\) from the set. Does nothing if no such key exists.+--+-- @since 1.1.0.0+{-# INLINE delete_ #-}+delete_ :: (PrimMonad m) => IntSet (PrimState m) -> Int -> m ()+delete_ is k = void $ delete is k++-- | \(O(\log n)\) Deletes the minimum key from the set. Returns `Nothing` if the set is empty.+--+-- @since 1.1.0.0+{-# INLINE deleteMin #-}+deleteMin :: (PrimMonad m) => IntSet (PrimState m) -> m (Maybe Int)+deleteMin is = do+ lookupMin is+ >>= mapM+ ( \key -> do+ delete_ is key+ pure key+ )++-- | \(O(\log n)\) Deletes the maximum key from the set. Returns `Nothing` if the set is empty.+--+-- @since 1.1.0.0+{-# INLINE deleteMax #-}+deleteMax :: (PrimMonad m) => IntSet (PrimState m) -> m (Maybe Int)+deleteMax is = do+ lookupMax is+ >>= mapM+ ( \key -> do+ delete_ is key+ pure key+ )++-- | \(O(n \log n)\) Enumerates the keys in the map.+--+-- @since 1.1.0.0+{-# INLINE keys #-}+keys :: (PrimMonad m) => IntSet (PrimState m) -> m (VU.Vector Int)+keys is@IntSet {sizeIS} = do+ n <- VGM.unsafeRead sizeIS 0+ VU.unfoldrExactNM+ n+ ( \i -> do+ i' <- fromJust <$> lookupGT is i+ pure (i', i')+ )+ (-1)
+ src/AtCoder/Extra/IntervalMap.hs view
@@ -0,0 +1,462 @@+{-# LANGUAGE DerivingStrategies #-}++-- original implementation:+-- <https://noimi.hatenablog.com/entry/2021/05/02/195143>++-- | Dense map covering \([0, n)\) that manages non-overlapping intervals \([l, r)\) within it. Each+-- interval has an associated value \(v\). Use @onAdd@ and @onDel@ hooks to track interval state+-- changes during `buildM`, `insertM` and `deleteM` operations.+--+-- ==== Invariant+-- Each interval is operated as a whole, similar to a persistant data structure. When part of an+-- inerval is modified, the whole interval is deleted first, and the subintervals are re-inserted.+-- It's important for tracking non-linear interval information with the @onAdd@ and @onDel@ hooks+-- (callbacks).+--+-- ==== __Example__+-- Create an `IntervalMap` that covers a half-open interval \([0, n)\):+--+-- >>> import AtCoder.Extra.IntervalMap qualified as ITM+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> import Data.Vector.Unboxed.Mutable qualified as VUM+-- >>> itm <- ITM.new @_ @Int 4+--+-- It handles range set queries in amortized \(O(\log n)\) time:+--+-- >>> ITM.insert itm 0 4 0 -- 0 0 0 0+-- >>> ITM.insert itm 1 3 1 -- 0 1 1 0+-- >>> ITM.freeze itm+-- [(0,(1,0)),(1,(3,1)),(3,(4,0))]+--+-- Track interval informations with the @onAdd@ and @onDel@ hooks:+--+-- >>> import Debug.Trace (traceShow)+-- >>> itm <- ITM.new @_ @Int 4+-- >>> let onAdd l r x = print ("onAdd", l, r, x)+-- >>> let onDel l r x = print ("onDel", l, r, x)+--+-- >>> ITM.insertM itm 0 4 0 onAdd onDel -- 0 0 0 0+-- ("onAdd",0,4,0)+--+-- >>> ITM.insertM itm 1 3 1 onAdd onDel -- 0 1 1 0+-- ("onDel",0,4,0)+-- ("onAdd",0,1,0)+-- ("onAdd",3,4,0)+-- ("onAdd",1,3,1)+--+-- >>> ITM.deleteM itm 0 4 onAdd onDel+-- ("onDel",0,1,0)+-- ("onDel",1,3,1)+-- ("onDel",3,4,0)+--+-- @since 1.1.0.0+module AtCoder.Extra.IntervalMap+ ( -- * IntervalMap+ IntervalMap,++ -- * Constructors+ new,+ build,+ buildM,++ -- * Metadata+ capacity,++ -- * Lookups+ contains,+ intersects,+ lookup,+ read,+ readMaybe,++ -- * Modifications++ -- ** Insertions+ insert,+ insertM,++ -- ** Deletions+ delete,+ deleteM,++ -- ** Overwrites+ overwrite,+ overwriteM,++ -- * Conversions+ freeze,+ )+where++import AtCoder.Extra.IntMap qualified as IM+import Control.Monad (foldM_)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Vector.Generic qualified as G+import Data.Vector.Unboxed qualified as VU+import GHC.Stack (HasCallStack)+import Prelude hiding (lookup, read)++-- | Dense map covering \([0, n)\) that manages non-overlapping intervals \((l, r)\) within it. Each+-- interval has an associated value \(x\). Use @onAdd@ and @onDel@ hooks to track interval state+-- changes during `buildM`, `insertM` and `deleteM` operations.+--+-- @since 1.1.0.0+newtype IntervalMap s a = IntervalMap+ { -- | Maps \(l\) to \((r, a)\).+ unITM :: IM.IntMap s (Int, a)+ }++-- | \(O(n)\) Creates an empty `IntervalMap`.+--+-- @since 1.1.0.0+new :: (PrimMonad m, VU.Unbox a) => Int -> m (IntervalMap (PrimState m) a)+new = fmap IntervalMap . IM.new++-- | \(O(n + m \log n)\) Creates an `IntervalMap` by combining consecutive equal values into one+-- interval.+--+-- ==== __Example__+-- >>> itm <- build @_ @Int (VU.fromList [10,10,11,11,12,12])+-- >>> freeze itm+-- [(0,(2,10)),(2,(4,11)),(4,(6,12))]+--+-- @since 1.1.0.0+build :: (PrimMonad m, Eq a, VU.Unbox a) => VU.Vector a -> m (IntervalMap (PrimState m) a)+build xs = buildM xs onAdd+ where+ onAdd _ _ _ = pure ()++-- | \(O(n + m \log n)\) Creates an `IntervalMap` by combining consecutive equal values into one+-- interval, while performing @onAdd@ hook for each interval.+--+-- @since 1.1.0.0+buildM ::+ (PrimMonad m, Eq a, VU.Unbox a) =>+ -- | Input values+ VU.Vector a ->+ -- | @onAdd@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ -- | The map+ m (IntervalMap (PrimState m) a)+buildM xs onAdd = do+ dim <- IM.new (G.length xs)+ foldM_ (step dim) (0 :: Int) $ G.group xs+ pure $ IntervalMap dim+ where+ step dim !l !xs' = do+ let !l' = l + G.length xs'+ IM.insert dim l (l', G.head xs')+ onAdd l l' (G.head xs')+ pure l'++-- | \(O(1)\) Returns the capacity \(n\), where the interval \([0, n)\) is managed by the map.+--+-- @since 1.1.0.0+{-# INLINE capacity #-}+capacity :: IntervalMap s a -> Int+capacity = IM.capacity . unITM++-- | \(O(\log n)\) Returns whether a point \(x\) is contained within any of the intervals.+--+-- @since 1.1.0.0+contains :: (PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> m Bool+contains itm i = intersects itm i (i + 1)++-- | \(O(\log n)\) Returns whether an interval \([l, r)\) is fully contained within any of the+-- intervals.+--+-- @since 1.1.0.0+intersects :: (PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m Bool+intersects (IntervalMap dim) l r+ | l >= r = pure False+ | otherwise = do+ res <- IM.lookupLE dim l+ pure $ case res of+ Just (!_, (!r', !_)) -> r <= r'+ _ -> False++-- | \(O(\log n)\) Looks up an interval that fully contains \([l, r)\).+--+-- @since 1.1.0.0+lookup :: (PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m (Maybe (Int, Int, a))+lookup (IntervalMap im) l r+ | l >= r = pure Nothing+ | otherwise = do+ res <- IM.lookupLE im l+ pure $ case res of+ Just (!l', (!r', !a))+ | r <= r' -> Just (l', r', a)+ _ -> Nothing++-- | \(O(\log n)\) Looks up an interval that fully contains \([l, r)\) and reads out the value.+-- Throws an error if no such interval exists.+--+-- @since 1.1.0.0+read :: (HasCallStack, PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m a+read itm l r = do+ res <- readMaybe itm l r+ pure $ case res of+ Just !a -> a+ Nothing -> error $ "[read] not a member: " ++ show (l, r)++-- | \(O(\log n)\) Looks up an interval that fully contains \([l, r)\) and reads out the value.+-- Returns `Nothing` if no such interval exists.+--+-- @since 1.1.0.0+readMaybe :: (PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m (Maybe a)+readMaybe (IntervalMap dim) l r+ | l >= r = pure Nothing+ | otherwise = do+ res <- IM.lookupLE dim l+ pure $ case res of+ Just (!_, (!r', !a))+ | r <= r' -> Just a+ _ -> Nothing++-- | Amortized \(O(\log n)\) Inserts an interval \([l, r)\) with associated value \(v\) into the+-- map. Overwrites any overlapping intervals.+--+-- @since 1.1.0.0+insert :: (PrimMonad m, Eq a, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> a -> m ()+insert itm l r x = insertM itm l r x onAdd onDel+ where+ onAdd _ _ _ = pure ()+ onDel _ _ _ = pure ()++-- | Amortized \(O(\log n)\) Inserts an interval \([l, r)\) with associated value \(v\) into the+-- map. Overwrites any overlapping intervals. Tracks interval state changes via @onAdd@ and @onDel@+-- hooks.+--+-- @since 1.1.0.0+insertM ::+ (PrimMonad m, Eq a, VU.Unbox a) =>+ -- | The map+ IntervalMap (PrimState m) a ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(v\)+ a ->+ -- | @onAdd@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ -- | @onDel@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ m ()+insertM (IntervalMap dim) l0 r0 x onAdd onDel+ | l0 >= r0 = pure ()+ | otherwise = do+ !r <- handleRight l0 r0+ (!l', !r') <- handleLeft l0 r+ onAdd l' r' x+ IM.insert dim l' (r', x)+ where+ handleRight l r = do+ res <- IM.lookupGE dim l+ case res of+ Just interval0@(!_, (!_, !_)) -> run interval0 l r+ Nothing -> pure r++ -- Looks into intervals with @l' >= l0@.+ -- [----]+ -- (i) *--------] overwrite if it's x+ -- (ii) [-------]* delete anyways+ -- (iii) *(------] overwrite if it's x, or+ run (!l', (!r', !x')) l r+ | l' > r = do+ -- not adjacent: end.+ pure r+ -- (i)+ | l' == r && x' == x = do+ -- adjacent interval with the same value: merge into one.+ onDel l' r' x'+ IM.delete_ dim l'+ pure r'+ | l' == r = do+ -- adjacent interval with different values: nothing to do.+ pure r+ -- (ii)+ | r' <= r = do+ -- inside the interval: delete and continue+ onDel l' r' x'+ IM.delete_ dim l'+ res <- IM.lookupGT dim l'+ case res of+ Just rng -> run rng l r+ Nothing -> pure r+ -- (iii)+ | x' == x = do+ -- intersecting interval with the same value: merge into one.+ onDel l' r' x'+ IM.delete_ dim l'+ pure r'+ | otherwise = do+ -- intersecting interval with a different value: delete the intersection.+ onDel l' r' x'+ onAdd r r' x'+ IM.delete_ dim l'+ IM.insert dim r (r', x')+ pure r++ handleLeft l r = do+ res <- IM.lookupLT dim l+ case res of+ Nothing -> pure (l, r)+ Just (!l', (!r', !x'))+ -- (i): adjacent interval+ | r' == l && x' == x -> do+ -- adjacent interval with the same value: merge into one.+ onDel l' r' x'+ IM.delete_ dim l'+ pure (l', r)+ | r' == l -> do+ -- adjacent interval with different values: nothing to do.+ pure (l, r)+ -- (ii): not adjacent or intersecting+ | r' < l -> do+ pure (l, r)+ -- (iii): intersecting+ | x' == x -> do+ -- insersecting interval with the same value: merge into one.+ onDel l' r' x'+ IM.delete_ dim l'+ pure (min l l', max r r')+ | r' > r -> do+ -- [l', r') contains [l, r) with a different value: split into three.+ onDel l' r' x'+ onAdd l' l x'+ onAdd r r' x'+ -- IM.delete_ dim l'+ IM.insert dim l' (l, x')+ IM.insert dim r (r', x')+ pure (l, r)+ | otherwise -> do+ -- insersecting interval with a different value: delete.+ onDel l' r' x'+ onAdd l' l x'+ -- IM.delete_ dim l'+ IM.insert dim l' (l, x')+ pure (l, r)++-- | Amortized \(O(\log n)\) Deletes an interval \([l, r)\) from the map.+--+-- @since 1.1.0.0+delete :: (PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> m ()+delete itm l r = deleteM itm l r onAdd onDel+ where+ onAdd _ _ _ = pure ()+ onDel _ _ _ = pure ()++-- | Amortized \(O(\log n)\) Deletes an interval \([l, r)\) from the map. Tracks interval state+-- changes via @onAdd@ and @onDel@ hooks.+--+-- @since 1.1.0.0+deleteM ::+ (PrimMonad m, VU.Unbox a) =>+ -- | The map+ IntervalMap (PrimState m) a ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | @onAdd@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ -- | @onDel@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ m ()+deleteM (IntervalMap dim) l0 r0 onAdd onDel+ | l0 >= r0 = pure ()+ | otherwise = do+ handleRight l0 r0+ handleLeft l0 r0+ where+ handleRight l r = do+ res <- IM.lookupGE dim l+ case res of+ Just interval0@(!_, (!_, !_)) -> run interval0 l r+ Nothing -> pure ()++ run (!l', (!r', !x')) l r+ | l' >= r = do+ -- not intersecting+ pure ()+ | r' <= r = do+ -- contained+ onDel l' r' x'+ IM.delete_ dim l'+ res <- IM.lookupGT dim l'+ case res of+ Just rng -> run rng l r+ Nothing -> pure ()+ | otherwise = do+ -- intersecting+ onDel l' r' x'+ onAdd r r' x'+ IM.delete_ dim l'+ IM.insert dim r (r', x')+ pure ()++ handleLeft l r = do+ res <- IM.lookupLT dim l+ case res of+ Nothing -> pure ()+ Just (!l', (!r', !x'))+ | r' <= l -> do+ -- not intersecting+ pure ()+ | r' > r -> do+ -- [l', r') contains [l, r)+ onDel l' r' x'+ onAdd l' l x'+ onAdd r r' x'+ -- IM.delete dim l'+ IM.insert dim l' (l, x')+ IM.insert dim r (r', x')+ | otherwise -> do+ -- intersecting+ onDel l' r' x'+ onAdd l' l x'+ -- IM.delete_ dim l'+ IM.insert dim l' (l, x')++-- | \(O(\log n)\) Shorthand for overwriting the value of an interval that contains \([l, r)\).+--+-- @since 1.1.0.0+overwrite :: (PrimMonad m, Eq a, VU.Unbox a) => IntervalMap (PrimState m) a -> Int -> Int -> a -> m ()+overwrite itm l r x = do+ res <- lookup itm l r+ case res of+ Just (!l', !r', !_) -> insert itm l' r' x+ Nothing -> pure ()++-- | \(O(\log n)\). Shorthand for overwriting the value of an interval that contains \([l, r)\).+-- Tracks interval state changes via @onAdd@ and @onDel@ hooks.+--+-- @since 1.1.0.0+overwriteM ::+ (PrimMonad m, Eq a, VU.Unbox a) =>+ -- | The map+ IntervalMap (PrimState m) a ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(v\)+ a ->+ -- | @onAdd@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ -- | @onDel@ hook that take an interval \([l, r)\) with associated value \(v\)+ (Int -> Int -> a -> m ()) ->+ m ()+overwriteM itm l r x onAdd onDel = do+ res <- lookup itm l r+ case res of+ Just (!l', !r', !_) -> insertM itm l' r' x onAdd onDel+ Nothing -> pure ()++-- | \(O(n \log n)\) Enumerates the intervals and the associated values as \((l, (r, x))\) tuples,+-- where \([l, r)\) is the interval and \(x\) is the associated value.+--+-- @since 1.1.0.0+freeze :: (PrimMonad m, VU.Unbox a) => IntervalMap (PrimState m) a -> m (VU.Vector (Int, (Int, a)))+freeze = IM.assocs . unITM
src/AtCoder/Extra/Math.hs view
@@ -1,34 +1,50 @@ -- | Extra math module. ----- ==== Examples--- >>> import AtCoder.Extra.Math qualified as M--- >>> import Data.Semigroup (Product(..), Sum(..))--- >>> getProduct $ M.power (<>) 32 (Product 2)--- 4294967296------ >>> getProduct $ M.stimes' 32 (Product 2)--- 4294967296------ >>> getProduct $ M.mtimes' 32 (Product 2)--- 4294967296--- -- @since 1.0.0.0 module AtCoder.Extra.Math- ( -- * Binary exponential+ ( -- * Re-exports from the internal math module+ isPrime32,+ ACIM.invGcd,+ ACIM.primitiveRoot,++ -- * Binary exponentiation++ -- | ==== __Examples__+ -- >>> import AtCoder.Extra.Math qualified as M+ -- >>> import Data.Semigroup (Product(..), Sum(..))+ -- >>> getProduct $ M.power (<>) 32 (Product 2)+ -- 4294967296+ --+ -- >>> getProduct $ M.stimes' 32 (Product 2)+ -- 4294967296+ --+ -- >>> getProduct $ M.mtimes' 32 (Product 2)+ -- 4294967296 power, stimes', mtimes', ) where +import AtCoder.Internal.Math qualified as ACIM import Data.Bits ((.>>.)) --- TODO: add `HasCallStack` and provide with `unsafePower`.+-- | \(O(k \log^3 n) (k = 3)\). Returns whether the given `Int` value is a prime number.+--+-- ==== Constraints+-- - \(n < 4759123141 (2^{32} < 4759123141)\), otherwise the return value can lie+-- (see [Wikipedia](https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Testing_against_small_sets_of_bases)).+--+--+-- @since 1.1.0.0+{-# INLINE isPrime32 #-}+isPrime32 :: Int -> Bool+isPrime32 = ACIM.isPrime --- | Calculates \(s^n\) with custom multiplication operator using the binary exponentiation+-- | Calculates \(x^n\) with custom multiplication operator using the binary exponentiation -- technique. ----- The internal implementation is taken from `Data.Semigroup.stimes`, but `power` uses strict+-- The internal implementation is taken from @Data.Semigroup.stimes@, but `power` uses strict -- evaluation and is often much faster. -- -- ==== Complexity@@ -53,7 +69,7 @@ | n == 1 = x `op` z | otherwise = g (x `op` x) (n .>>. 1) (x `op` z) --- | Strict `Data.Semigroup.stimes`.+-- | Strict variant of @Data.Semigroup.stimes@. -- -- ==== Complexity -- - \(O(\log n)\)@@ -66,7 +82,7 @@ stimes' :: (Semigroup a) => Int -> a -> a stimes' = power (<>) --- | Strict `Data.Monoid.mtimes`.+-- | Strict variant of @Data.Monoid.mtimes@. -- -- ==== Complexity -- - \(O(\log n)\)
src/AtCoder/Extra/Monoid.hs view
@@ -1,31 +1,42 @@ {-# LANGUAGE TypeFamilies #-} --- | Extra module of pre-defined `SegAct` instances.------ Be warned that they're not 100% guaranteed to be correct.+-- | Extra module of pre-defined `SegAct` instances and helpful monoids. -- -- @since 1.0.0.0 module AtCoder.Extra.Monoid- ( -- * SegAct (re-export)+ ( -- * Re-exports++ -- | It's mainly a list. It is recommended to use specific submodules.++ -- ** SegAct SegAct (..), - -- * Affine1+ -- ** Affine1 Affine1 (..), Affine1Repr, - -- * Range add+ -- ** Mat2x2+ Mat2x2 (..),+ Mat2x2Repr,+ V2 (..),+ V2Repr,++ -- ** Range add RangeAdd (..),- RangeAddId (..), - -- * Range set+ -- ** Range set RangeSet (..),- RangeSetId (..),+ RangeSetRepr,++ -- ** Rolling hash+ RollingHash, ) where import AtCoder.Extra.Monoid.Affine1 (Affine1 (..), Affine1Repr)+import AtCoder.Extra.Monoid.Mat2x2 (Mat2x2 (..), Mat2x2Repr) import AtCoder.Extra.Monoid.RangeAdd (RangeAdd (..))-import AtCoder.Extra.Monoid.RangeAddId (RangeAddId (..))-import AtCoder.Extra.Monoid.RangeSet (RangeSet (..))-import AtCoder.Extra.Monoid.RangeSetId (RangeSetId (..))+import AtCoder.Extra.Monoid.RangeSet (RangeSet (..), RangeSetRepr)+import AtCoder.Extra.Monoid.RollingHash (RollingHash)+import AtCoder.Extra.Monoid.V2 (V2 (..), V2Repr) import AtCoder.LazySegTree (SegAct (..))
src/AtCoder/Extra/Monoid/Affine1.hs view
@@ -1,17 +1,23 @@ {-# LANGUAGE TypeFamilies #-} --- | Range add monoid action for \([l, r)\) intervals: \(f: x \rightarrow ax + b\).+-- | Monoid action \(f: x \rightarrow ax + b\). --+-- - Use @Mat2x2@ if inverse operations are required, or if it's necessary to store the monoid+-- length in the acted monoid (@V2@).+-- -- @since 1.0.0.0 module AtCoder.Extra.Monoid.Affine1 ( -- * Affine1 Affine1 (..), Affine1Repr, - -- * Constructor+ -- * Constructors new,+ unAffine1,+ ident,+ zero, - -- * Action+ -- * Actions act, ) where@@ -27,17 +33,16 @@ import Data.Vector.Unboxed qualified as VU import Data.Vector.Unboxed.Mutable qualified as VUM --- Tuple is not the fastest representation, but it's easier to implement `Unbox`.---- | Range add monoid action for \([l, r)\) intervals: \(f: x \rightarrow ax + b\).+-- | Monoid action \(f: x \rightarrow ax + b\). --+-- - Use @Mat2x2@ if inverse operations are required, or if it's necessary to store the monoid+-- length in the acted monoid (@V2@).+-- -- ==== Composition and dual--- `Semigroup` for `Affine1` is implemented like function composition, and rightmost affine--- transformation is applied first: \((f_1 \circ f_2) v := f_1 (f_2(v))\). If you need 'foldr'--- of \([f_l, f_{l+1}, .., f_r)\) on a segment tree, be sure to wrap `Affine1` in--- `Data.Monoid.Dual`.+-- The affine transformation acts as a left monoid action: \(f_2 (f_1 v) = (f_2 \circ f_1) v\). To+-- apply the leftmost transformation first in a segment tree, wrap `Affine1` in @Data.Monoid.Dual@. ----- ==== Example+-- ==== __Example__ -- >>> import AtCoder.Extra.Monoid (SegAct(..), Affine1(..)) -- >>> import AtCoder.LazySegTree qualified as LST -- >>> seg <- LST.build @_ @(Affine1 Int) @(Sum Int) $ VU.generate 3 Sum -- [0, 1, 2]@@ -62,21 +67,42 @@ -- @since 1.0.0.0 type Affine1Repr a = (a, a) --- | Creates `Affine1`.+-- | \(O(1)\) Creates a one-dimensional affine transformation: \(f: x \rightarrow a \times x + b\). -- -- @since 1.0.0.0 {-# INLINE new #-} new :: a -> a -> Affine1 a new !a !b = Affine1 (a, b) --- | Applies \(f: x \rightarrow a \times x + b\).+-- | \(O(1)\) Retrieves the two components of `Affine1`. --+-- @since 1.1.0.0+{-# INLINE unAffine1 #-}+unAffine1 :: Affine1 a -> Affine1Repr a+unAffine1 (Affine1 a) = a++-- | \(O(1)\) Identity transformation.+--+-- @since 1.1.0.0+{-# INLINE ident #-}+ident :: (Num a) => Affine1 a+ident = Affine1 (1, 0)++-- | \(O(1)\) Transformation to zero.+--+-- @since 1.1.0.0+{-# INLINE zero #-}+zero :: (Num a) => Affine1 a+zero = Affine1 (0, 0)++-- | \(O(1)\) Applies the one-dimensional affine transformation \(f: x \rightarrow a \times x + b\).+-- -- @since 1.0.0.0 {-# INLINE act #-} act :: (Num a) => Affine1 a -> a -> a act (Affine1 (!a, !b)) x = a * x + b --- | Acts on @a@ with length in terms of `SegAct`. Works for `Sum a` only.+-- | \(O(1)\) Acts on @a@ with length in terms of `SegAct`. Works for `Sum a` only. -- -- @since 1.0.0.0 {-# INLINE actWithLength #-}
+ src/AtCoder/Extra/Monoid/Mat2x2.hs view
@@ -0,0 +1,202 @@+{-# LANGUAGE TypeFamilies #-}++-- | Monoid action \(f: x \rightarrow ax + b\). Less efficient than @Affine1@, but compatible with+-- inverse opereations.+--+-- @since 1.1.0.0+module AtCoder.Extra.Monoid.Mat2x2+ ( -- * Mat2x2+ Mat2x2 (..),+ Mat2x2Repr,++ -- * Constructors+ new,+ unMat2x2,+ ident,+ zero,++ -- * Actions+ act,++ -- * Operators+ map,+ det,+ inv,+ )+where++import AtCoder.Extra.Math qualified as ACEM+import AtCoder.Extra.Monoid.V2 (V2 (..))+import AtCoder.LazySegTree (SegAct (..))+import Data.Semigroup (Dual (..), Semigroup (..))+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 (map)++-- | Monoid action \(f: x \rightarrow ax + b\). Less efficient than @Affine1@, but compatible with+-- inverse opereations.+--+-- ==== Composition and dual+-- The affine transformation acts as a left monoid action: \(f_2 (f_1 v) = (f_2 \circ f_1) v\). To+-- apply the leftmost transformation first in a segment tree, wrap `Mat2x2` in @Data.Monoid.Dual@.+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Monoid.Mat2x2 qualified as Mat2x2+-- >>> import AtCoder.Extra.Monoid.V2 qualified as V2+-- >>> import AtCoder.Extra.Monoid (SegAct(..), Mat2x2(..), V2(..))+-- >>> import AtCoder.LazySegTree qualified as LST+-- >>> seg <- LST.build @_ @(Mat2x2 Int) @(V2 Int) $ VU.generate 3 V2.new -- [0, 1, 2]+-- >>> LST.applyIn seg 0 3 $ Mat2x2.new 2 1 -- [1, 3, 5]+-- >>> V2.unV2 <$> LST.allProd seg+-- 9+--+-- @since 1.1.0.0+newtype Mat2x2 a = Mat2x2 (Mat2x2Repr a)+ deriving newtype+ ( -- | @since 1.1.0.0+ Eq,+ -- | @since 1.1.0.0+ Ord,+ -- | @since 1.1.0.0+ Show+ )++-- | `Mat2x2` internal representation. Tuples are not the fastest representation, but it's easier+-- to implement `Data.Vector.Unboxed.Unbox`.+--+-- @since 1.1.0.0+type Mat2x2Repr a = (a, a, a, a)++-- | \(O(1)\) Creates a one-dimensional affine transformation: \(f: x \rightarrow a \times x + b\).+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (Num a) => a -> a -> Mat2x2 a+new !a !b = Mat2x2 (a, b, 0, 1)++-- | \(O(1)\) Retrieves the four components of `Mat2x2`.+--+-- @since 1.1.0.0+{-# INLINE unMat2x2 #-}+unMat2x2 :: Mat2x2 a -> Mat2x2Repr a+unMat2x2 (Mat2x2 a) = a++-- | \(O(1)\) Transformation to zero.+--+-- @since 1.1.0.0+{-# INLINE zero #-}+zero :: (Num a) => Mat2x2 a+zero = Mat2x2 (0, 0, 0, 0)++-- | \(O(1)\) Identity transformation.+--+-- @since 1.1.0.0+{-# INLINE ident #-}+ident :: (Num a) => Mat2x2 a+ident = Mat2x2 (1, 0, 0, 1)++-- | \(O(1)\) Multiplies `Mat2x2` to `V2`.+{-# INLINE mulMV #-}+mulMV :: (Num a) => Mat2x2 a -> V2 a -> V2 a+mulMV (Mat2x2 (!a11, !a12, !a21, !a22)) (V2 (!x1, !x2)) = V2 (a', b')+ where+ !a' = a11 * x1 + a12 * x2+ !b' = a21 * x1 + a22 * x2++-- | \(O(1)\) Multiplies `Mat2x2` to `Mat2x2`.+{-# INLINE mulMM #-}+mulMM :: (Num a) => Mat2x2 a -> Mat2x2 a -> Mat2x2 a+mulMM (Mat2x2 (!a11, !a12, !a21, !a22)) (Mat2x2 (!b11, !b12, !b21, !b22)) = Mat2x2 (c11, c12, c21, c22)+ where+ !c11 = a11 * b11 + a12 * b21+ !c12 = a11 * b12 + a12 * b22+ !c21 = a21 * b11 + a22 * b21+ !c22 = a21 * b12 + a22 * b22++-- | \(O(1)\) Multiplies `Mat2x2` to `V2`.+--+-- @since 1.1.0.0+{-# INLINE act #-}+act :: (Num a) => Mat2x2 a -> V2 a -> V2 a+act = mulMV++-- | \(O(1)\) Maps the every component of `Mat2x2`.+--+-- @since 1.1.0.0+{-# INLINE map #-}+map :: (a -> b) -> Mat2x2 a -> Mat2x2 b+map f (Mat2x2 (!a11, !a12, !a21, !a22)) = Mat2x2 (a11', a12', a21', a22')+ where+ !a11' = f a11+ !a12' = f a12+ !a21' = f a21+ !a22' = f a22++-- | \(O(1)\) Returns the determinan of the matrix.+--+-- @since 1.1.0.0+{-# INLINE det #-}+det :: (Fractional e) => Mat2x2 e -> e+det (Mat2x2 (!a, !b, !c, !d)) = a * d - b * c++-- | \(O(1)\) Returns the inverse matrix, based on `Fractional` instance (mainly for @ModInt@).+--+-- ==== Constraints+-- - The determinant (`det`) of the matrix must be non-zero, otherwise an error is thrown.+--+-- @since 1.1.0.0+{-# INLINE inv #-}+inv :: (HasCallStack, Fractional e, Eq e) => Mat2x2 e -> Mat2x2 e+inv (Mat2x2 (!a, !b, !c, !d)) = Mat2x2 (a', b', c', d')+ where+ -- NOTE: zero division+ -- !r = recip $ a * d - b * c+ !r+ | det_ == 0 = error "AtCoder.Extra.Mat2x2.inv: the determinant of the matrix must be non zero"+ | otherwise = recip det_+ where+ !det_ = a * d - b * c+ !a' = r * d+ !b' = r * (-b)+ !c' = r * (-c)+ !d' = r * a++-- | @since 1.1.0.0+instance (Num a) => Semigroup (Mat2x2 a) where+ {-# INLINE (<>) #-}+ (<>) = mulMM+ {-# INLINE stimes #-}+ stimes = ACEM.stimes' . fromIntegral++-- | @since 1.1.0.0+instance (Num a) => Monoid (Mat2x2 a) where+ {-# INLINE mempty #-}+ mempty = ident++-- | @since 1.1.0.0+instance (Num a) => SegAct (Mat2x2 a) (V2 a) where+ {-# INLINE segAct #-}+ segAct = mulMV++-- | @since 1.1.0.0+instance (Num a) => SegAct (Dual (Mat2x2 a)) (V2 a) where+ {-# INLINE segAct #-}+ segAct (Dual f) = mulMV f++-- | @since 1.1.0.0+newtype instance VU.MVector s (Mat2x2 a) = MV_Mat2x2 (VU.MVector s (Mat2x2Repr a))++-- | @since 1.1.0.0+newtype instance VU.Vector (Mat2x2 a) = V_Mat2x2 (VU.Vector (Mat2x2Repr a))++-- | @since 1.1.0.0+deriving instance (VU.Unbox a) => VGM.MVector VUM.MVector (Mat2x2 a)++-- | @since 1.1.0.0+deriving instance (VU.Unbox a) => VG.Vector VU.Vector (Mat2x2 a)++-- | @since 1.1.0.0+instance (VU.Unbox a) => VU.Unbox (Mat2x2 a)
src/AtCoder/Extra/Monoid/RangeAdd.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE TypeFamilies #-} --- | Range add monoid action for \([l, r)\) intervals.+-- | Monoid action \(f: x \rightarrow x + d\). -- -- @since 1.0.0.0 module AtCoder.Extra.Monoid.RangeAdd@@ -9,27 +9,28 @@ -- * Constructor new,+ unRangeAdd, - -- * Action+ -- * Actions act, ) where import AtCoder.LazySegTree (SegAct (..))-import Data.Semigroup (Sum (..))+import Data.Semigroup (stimes, Sum (..), Max(..), Min(..)) 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 --- | Range add monoid action.+-- | Monoid action \(f: x \rightarrow x + d\). ----- ==== Example+-- ==== __Example__ -- >>> import AtCoder.Extra.Monoid (SegAct(..), RangeAdd(..)) -- >>> import AtCoder.LazySegTree qualified as LST -- >>> import Data.Semigroup (Max(..))--- >>> seg <- LST.build @_ @(RangeAdd Int) @(Sum Int) $ VU.generate 3 Sum -- [0, 1, 2]--- >>> LST.applyIn seg 0 3 $ RangeAdd 5 -- [5, 6, 7]+-- >>> seg <- LST.build @_ @(RangeAdd (Sum Int)) @(Sum Int) $ VU.generate 3 Sum -- [0, 1, 2]+-- >>> LST.applyIn seg 0 3 $ RangeAdd (Sum 5) -- [5, 6, 7] -- >>> getSum <$> LST.prod seg 0 3 -- 18 --@@ -51,36 +52,51 @@ new :: a -> RangeAdd a new = RangeAdd --- | Applies one-length range add: \(f: x \rightarrow d + x\).+-- | \(O(1)\) Retrieves the internal value of `RangeAdd`. --+-- @since 1.1.0.0+{-# INLINE unRangeAdd #-}+unRangeAdd :: RangeAdd a -> a+unRangeAdd (RangeAdd a) = a++-- | \(O(1)\) Applies one-length range add: \(f: x \rightarrow d + x\).+-- -- @since 1.0.0.0 {-# INLINE act #-}-act :: (Num a) => RangeAdd a -> a -> a-act (RangeAdd dx) x = dx + x+act :: (Semigroup a) => RangeAdd a -> a -> a+act (RangeAdd dx) x = dx <> x --- | Acts on @a@ with length in terms of `SegAct`.+-- | \(O(1)\) Acts on @a@ with length in terms of `SegAct`. -- -- @since 1.0.0.0 {-# INLINE actWithLength #-}-actWithLength :: (Num a) => Int -> RangeAdd a -> a -> a-actWithLength len (RangeAdd f) x = fromIntegral len * f + x+actWithLength :: (Semigroup a) => Int -> RangeAdd a -> a -> a+actWithLength len (RangeAdd f) x = stimes len f <> x -- | @since 1.0.0.0-instance (Num a) => Semigroup (RangeAdd a) where+instance (Semigroup a) => Semigroup (RangeAdd a) where {-# INLINE (<>) #-}- (RangeAdd a) <> (RangeAdd b) = RangeAdd $! a + b+ (RangeAdd a) <> (RangeAdd b) = RangeAdd $! a <> b --- | @since 1.0.0.0-instance (Num a) => Monoid (RangeAdd a) where+-- | @since 1.1.0.0+instance (Monoid a) => Monoid (RangeAdd a) where {-# INLINE mempty #-}- mempty = RangeAdd 0+ mempty = RangeAdd mempty --- | @since 1.0.0.0-instance (Num a) => SegAct (RangeAdd a) (Sum a) where+-- | @since 1.1.0.0+instance (Monoid (Sum a)) => SegAct (RangeAdd (Sum a)) (Sum a) where {-# INLINE segActWithLength #-}- segActWithLength len a (Sum x) = Sum $! actWithLength len a x+ segActWithLength len f x = actWithLength len f x --- not works as SegAct for Product, Min, and Max.+-- | @since 1.1.0.0+instance (Monoid (Max a)) => SegAct (RangeAdd (Max a)) (Max a) where+ {-# INLINE segActWithLength #-}+ segActWithLength len f x = actWithLength len f x++-- | @since 1.1.0.0+instance (Monoid (Min a)) => SegAct (RangeAdd (Min a)) (Min a) where+ {-# INLINE segActWithLength #-}+ segActWithLength len f x = actWithLength len f x -- | @since 1.0.0.0 newtype instance VU.MVector s (RangeAdd a) = MV_RangeAdd (VU.MVector s a)
− src/AtCoder/Extra/Monoid/RangeAddId.hs
@@ -1,95 +0,0 @@-{-# LANGUAGE TypeFamilies #-}---- | Range add monoid action for \([l, r)\) intervals. Works on ideomponent monoids such as `Max`--- or `Min` only.------ @since 1.0.0.0-module AtCoder.Extra.Monoid.RangeAddId- ( -- * RangeAddId- RangeAddId (..),- -- * Constructor- new,- -- * Action- act,- )-where--import AtCoder.LazySegTree (SegAct (..))-import Data.Semigroup (Max (..), Min (..))-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---- | Range add monoid action.------ ==== Example--- >>> import AtCoder.Extra.Monoid (SegAct(..), RangeAddId(..))--- >>> import AtCoder.LazySegTree qualified as LST--- >>> import Data.Semigroup (Max(..))--- >>> seg <- LST.build @_ @(RangeAddId Int) @(Max Int) $ VU.generate 3 Max -- [0, 1, 2]--- >>> LST.applyIn seg 0 3 $ RangeAddId 5 -- [5, 6, 7]--- >>> getMax <$> LST.prod seg 0 3--- 7------ @since 1.0.0.0-newtype RangeAddId a = RangeAddId a- deriving newtype- ( -- | @since 1.0.0.0- Eq,- -- | @since 1.0.0.0- Ord,- -- | @since 1.0.0.0- Show- )---- | Creates `RangeAddId`.------ @since 1.0.0.0-{-# INLINE new #-}-new :: a -> RangeAddId a-new = RangeAddId---- | Applies one-length range add: \(f: x \rightarrow d + x\).------ @since 1.0.0.0-{-# INLINE act #-}-act :: (Num a) => RangeAddId a -> a -> a-act (RangeAddId f) x = f + x---- | @since 1.0.0.0-instance (Num a) => Semigroup (RangeAddId a) where- {-# INLINE (<>) #-}- (RangeAddId a) <> (RangeAddId b) = RangeAddId $! a + b---- | @since 1.0.0.0-instance (Num a) => Monoid (RangeAddId a) where- {-# INLINE mempty #-}- mempty = RangeAddId 0---- | @since 1.0.0.0-instance (Num a) => SegAct (RangeAddId a) (Max a) where- {-# INLINE segAct #-}- segAct f (Max x) = Max $! act f x---- | @since 1.0.0.0-instance (Num a) => SegAct (RangeAddId a) (Min a) where- {-# INLINE segAct #-}- segAct f (Min x) = Min $! act f x---- not works as SegAct for Sum and Product.---- | @since 1.0.0.0-newtype instance VU.MVector s (RangeAddId a) = MV_RangeAddId (VU.MVector s a)---- | @since 1.0.0.0-newtype instance VU.Vector (RangeAddId a) = V_RangeAddId (VU.Vector a)---- | @since 1.0.0.0-deriving instance (VU.Unbox a) => VGM.MVector VUM.MVector (RangeAddId a)---- | @since 1.0.0.0-deriving instance (VU.Unbox a) => VG.Vector VU.Vector (RangeAddId a)---- | @since 1.0.0.0-instance (VU.Unbox a) => VU.Unbox (RangeAddId a)
src/AtCoder/Extra/Monoid/RangeSet.hs view
@@ -1,21 +1,22 @@ {-# LANGUAGE TypeFamilies #-} --- | Range set monoid action for \([l, r)\) intervals.+-- | Monoid action \(f: x \rightarrow a\). -- -- @since 1.0.0.0 module AtCoder.Extra.Monoid.RangeSet ( -- * RangeSet RangeSet (..),+ RangeSetRepr, - -- * Constructor+ -- * Constructors new,+ unRangeSet, - -- * Action+ -- * Actions act, ) where -import AtCoder.Extra.Math qualified as ACEM import AtCoder.LazySegTree (SegAct (..)) import Data.Bit (Bit (..)) import Data.Semigroup (stimes)@@ -24,9 +25,9 @@ import Data.Vector.Unboxed qualified as VU import Data.Vector.Unboxed.Mutable qualified as VUM --- | Range set monoid action.+-- | Monoid action \(f: x \rightarrow a\). ----- ==== Example+-- ==== __Example__ -- >>> import AtCoder.Extra.Monoid (SegAct(..), RangeSet(..)) -- >>> import AtCoder.LazySegTree qualified as LST -- >>> import Data.Bit (Bit (..))@@ -51,18 +52,25 @@ -- Tuples are not the fastest representation, but it's easier to implement -- `Data.Vector.Unboxed.Unbox`. ----- @since 1.0.0.0+-- @since 1.1.0.0 type RangeSetRepr a = (Bit, a) --- | Creates a new `RangeSet` action.+-- | \(O(1)\) Creates a new `RangeSet` action. -- -- @since 1.0.0.0 {-# INLINE new #-} new :: a -> RangeSet a new = RangeSet . (Bit True,) --- | Applies one-length range set: \(f: x \rightarrow y\).+-- | \(O(1)\) Retrieves the internal representation of `RangeSet`. --+-- @since 1.1.0.0+{-# INLINE unRangeSet #-}+unRangeSet :: RangeSet a -> RangeSetRepr a+unRangeSet (RangeSet a) = a++-- | \(O(1)\) Applies one-length range set: \(f: x \rightarrow y\).+-- -- @since 1.0.0.0 {-# INLINE act #-} act :: RangeSet a -> a -> a@@ -74,7 +82,7 @@ -- @since 1.0.0.0 {-# INLINE actWithLength #-} actWithLength :: (Semigroup a) => Int -> RangeSet a -> a -> a-actWithLength len (RangeSet (Bit True, !f)) _ = ACEM.power (<>) len f+actWithLength len (RangeSet (Bit True, !f)) _ = stimes len f actWithLength _ (RangeSet (Bit False, !_)) x = x -- | @since 1.0.0.0
− src/AtCoder/Extra/Monoid/RangeSetId.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE TypeFamilies #-}---- | Range set monoid action for \([l, r)\) intervals. Works on ideomponent monoids such as `Max`--- or `Min` only.--------- @since 1.0.0.0-module AtCoder.Extra.Monoid.RangeSetId- ( -- * RangeSetId- RangeSetId (..),-- -- * Constructor- new,-- -- * Action- act,- )-where--import AtCoder.LazySegTree (SegAct (..))-import Data.Bit (Bit (..))-import Data.Semigroup (Max (..), Min (..), stimes)-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---- | Range set monoid action.------ ==== Example--- >>> import AtCoder.Extra.Monoid (SegAct(..), RangeSetId(..))--- >>> import AtCoder.LazySegTree qualified as LST--- >>> import Data.Bit (Bit (..))--- >>> import Data.Semigroup (Max(..))--- >>> seg <- LST.build @_ @(RangeSetId (Max Int)) @(Max Int) $ VU.generate 3 (Max . (+ 10)) -- [10, 11, 12]--- >>> LST.applyIn seg 0 2 $ RangeSetId (Bit True, Max 5) -- [5, 5, 12]--- >>> getMax <$> LST.prod seg 0 3--- 12------ @since 1.0.0.0-newtype RangeSetId a = RangeSetId (RangeSetIdRepr a)- deriving newtype- ( -- | @since 1.0.0.0- Eq,- -- | @since 1.0.0.0- Ord,- -- | @since 1.0.0.0- Show- )---- | `RangeSetId` internal representation. The first value represents if it is an identity action.--- Tuples are not the fastest representation, but it's easier to implement--- `Data.Vector.Unboxed.Unbox`.------ @since 1.0.0.0-type RangeSetIdRepr a = (Bit, a)---- | Creates a new `RangeSet` action.------ @since 1.0.0.0-{-# INLINE new #-}-new :: a -> RangeSetId a-new = RangeSetId . (Bit True,)---- | Applies one-length range set: \(f: x \rightarrow y\).------ @since 1.0.0.0-{-# INLINE act #-}-act :: RangeSetId a -> a -> a-act (RangeSetId (Bit True, !f)) _ = f-act (RangeSetId (Bit False, !_)) x = x---- segActWithLength works for ideomponent monoids only.---- | @since 1.0.0.0-instance Semigroup (RangeSetId a) where- {-# INLINE (<>) #-}- RangeSetId (Bit False, !_) <> old = old- new_ <> _ = new_- {-# INLINE stimes #-}- stimes _ x = x---- The `Monoid` constraint is just for their default value.---- | @since 1.0.0.0-instance (Monoid a) => Monoid (RangeSetId a) where- {-# INLINE mempty #-}- mempty = RangeSetId (Bit False, mempty)- {-# INLINE mconcat #-}- -- find the first non-mempty- mconcat [] = mempty- mconcat (RangeSetId (Bit False, !_) : as) = mconcat as- mconcat (a : _) = a---- The target is limited to ideomponent monoids. The `Monoid` constraint is just for their default--- value.---- | @since 1.0.0.0-instance (Ord a, Bounded a) => SegAct (RangeSetId (Max a)) (Max a) where- {-# INLINE segAct #-}- segAct = act---- The target is limited to ideomponent monoids. The `Monoid` constraint is just for their default--- value.---- | @since 1.0.0.0-instance (Ord a, Bounded a) => SegAct (RangeSetId (Min a)) (Min a) where- {-# INLINE segAct #-}- segAct = act---- | @since 1.0.0.0-newtype instance VU.MVector s (RangeSetId a) = MV_RangeSetId (VU.MVector s (RangeSetIdRepr a))---- | @since 1.0.0.0-newtype instance VU.Vector (RangeSetId a) = V_RangeSetId (VU.Vector (RangeSetIdRepr a))---- | @since 1.0.0.0-deriving instance (VU.Unbox a) => VGM.MVector VUM.MVector (RangeSetId a)---- | @since 1.0.0.0-deriving instance (VU.Unbox a) => VG.Vector VU.Vector (RangeSetId a)---- | @since 1.0.0.0-instance (VU.Unbox a) => VU.Unbox (RangeSetId a)
+ src/AtCoder/Extra/Monoid/RollingHash.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}++-- | Rolling hash algorithm implemented as a monoid, typically stored in a segment tree. The type+-- parameters \(b\) and \(p\) represent the B-adic base and the modulus, respectively.+--+-- Combining `RollingHash` with `SegTree` enables \(O(\log |s|)\) string slice creation and+-- \(O(1)\) slice comparison.+--+-- @since 1.1.0.0+module AtCoder.Extra.Monoid.RollingHash+ ( -- * Rolling hash+ RollingHash (..),++ -- * Constructors+ new,+ unsafeNew,+ )+where++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.Exts (proxy#)+import GHC.TypeNats (KnownNat, natVal')++-- | Rolling hash algorithm implemented as a monoid, typically stored in a segment tree. The type+-- parameters \(b\) and \(p\) represent the B-adic base and the modulus, respectively.+--+-- Combining `RollingHash` with `SegTree` enables \(O(\log |s|)\) string slice creation and+-- \(O(1)\) slice comparison.+--+--+-- ==== __Example__+-- It's convenient to define a type alias of `RollingHash`:+--+-- >>> import AtCoder.Extra.Monoid.RollingHash qualified as RH+-- >>> import AtCoder.SegTree qualified as ST+-- >>> import Data.Char (ord)+-- >>> import Data.Semigroup (Dual (..))+-- >>> type RH = RH.RollingHash 100 998244353+--+-- Let's test whether "abcba" is a palindrome:+--+-- >>> seg <- ST.build @_ @RH . VU.map (RH.unsafeNew . ord) $ VU.fromList "abcba"+-- >>> seg' <- ST.build @_ @(Dual RH) . VU.map (Dual . RH.unsafeNew . ord) $ VU.fromList "abcba"+-- >>> hash1 <- ST.prod seg 2 5 -- cba (left to right)+-- >>> Dual hash2 <- ST.prod seg' 0 3 -- abc (right to lett)+-- >>> hash1 == hash2+-- True+--+-- @since 1.1.0.0+data RollingHash b p = RollingHash+ { -- | The hash value.+ hashRH :: {-# UNPACK #-} !Int,+ -- | \(b^{\mathrm{length}} \bmod p\).+ nextDigitRH :: {-# UNPACK #-} !Int+ }+ deriving+ ( -- | @since 1.1.0.0+ Eq,+ -- | @since 1.1.0.0+ Show+ )++-- | \(O(1)\) Creates a one-length `RollingHash` from an integer.+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: forall b p. (KnownNat b, KnownNat p) => Int -> RollingHash b p+new h = RollingHash (h `mod` fromIntegral (natVal' (proxy# @p))) (fromIntegral (natVal' (proxy# @b)))++-- | \(O(1)\) Creates a one-length `RollingHash` from an integer without taking the mod.+--+-- @since 1.1.0.0+{-# INLINE unsafeNew #-}+unsafeNew :: forall b p. (KnownNat b, KnownNat p) => Int -> RollingHash b p+unsafeNew h = RollingHash h (fromIntegral (natVal' (proxy# @b)))++-- | @since 1.1.0.0+instance (KnownNat b, KnownNat p) => Semigroup (RollingHash b p) where+ -- \| \(O(1)\)+ {-# INLINE (<>) #-}+ (RollingHash !digit1 !hash1) <> (RollingHash !digit2 !hash2) = RollingHash digit' hash'+ where+ !p = fromIntegral $ natVal' (proxy# @p)+ !digit' = digit1 * digit2 `mod` p+ !hash' = (hash1 * digit2 + hash2) `mod` p++-- | @since 1.1.0.0+instance (KnownNat b, KnownNat p) => Monoid (RollingHash b p) where+ {-# INLINE mempty #-}+ mempty = RollingHash 1 0++type RHRepr = (Int, Int)++-- | @since 1.1.0.0+instance VU.IsoUnbox (RollingHash b p) RHRepr where+ {-# INLINE toURepr #-}+ toURepr (RollingHash a b) = (a, b)+ {-# INLINE fromURepr #-}+ fromURepr (!a, !b) = RollingHash a b++-- | @since 1.1.0.0+newtype instance VU.MVector s (RollingHash b p) = MV_RH (VUM.MVector s RHRepr)++-- | @since 1.1.0.0+newtype instance VU.Vector (RollingHash b p) = V_RH (VU.Vector RHRepr)++-- | @since 1.1.0.0+deriving via (RollingHash b p `VU.As` RHRepr) instance VGM.MVector VUM.MVector (RollingHash b p)++-- | @since 1.1.0.0+deriving via (RollingHash b p `VU.As` RHRepr) instance VG.Vector VU.Vector (RollingHash b p)++-- | @since 1.1.0.0+instance VU.Unbox (RollingHash b p)
+ src/AtCoder/Extra/Monoid/V2.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE TypeFamilies #-}++-- | A monoid acted on by `Mat2x2`, an affine transformation target.+--+-- @since 1.1.0.0+module AtCoder.Extra.Monoid.V2+ ( -- * V2+ V2 (..),+ V2Repr,++ -- * Constructor+ new,+ unV2,+ )+where++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++-- | A monoid acted on by `Mat2x2`, an affine transformation target.+--+-- @since 1.1.0.0+newtype V2 a = V2 (V2Repr a)+ deriving newtype+ ( -- | @since 1.1.0.0+ Eq,+ -- | @since 1.1.0.0+ Ord,+ -- | @since 1.1.0.0+ Show+ )++-- | `V2` internal representation. Tuples are not the fastest representation, but it's easier+-- to implement `Data.Vector.Unboxed.Unbox`.+--+-- @since 1.1.0.0+type V2Repr a = (a, a)++-- | \(O(1)\) Creates `V2` of length \(1\).+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (Num a) => a -> V2 a+new !a = V2 (a, 1)++-- | \(O(1)\) Retrieves the value of `V2`, discarding the length information.+--+-- @since 1.1.0.0+{-# INLINE unV2 #-}+unV2 :: V2 a -> a+unV2 (V2 (!a, !_)) = a++-- | @since 1.1.0.0+instance (Num a) => Semigroup (V2 a) where+ {-# INLINE (<>) #-}+ (V2 (!a1, !a2)) <> (V2 (!b1, !b2)) = V2 (a', b')+ where+ !a' = a1 + b1+ !b' = a2 + b2++-- | @since 1.1.0.0+instance (Num a) => Monoid (V2 a) where+ {-# INLINE mempty #-}+ mempty = V2 (0, 0)++-- | @since 1.1.0.0+newtype instance VU.MVector s (V2 a) = MV_V2 (VU.MVector s (V2Repr a))++-- | @since 1.1.0.0+newtype instance VU.Vector (V2 a) = V_V2 (VU.Vector (V2Repr a))++-- | @since 1.1.0.0+deriving instance (VU.Unbox a) => VGM.MVector VUM.MVector (V2 a)++-- | @since 1.1.0.0+deriving instance (VU.Unbox a) => VG.Vector VU.Vector (V2 a)++-- | @since 1.1.0.0+instance (VU.Unbox a) => VU.Unbox (V2 a)
+ src/AtCoder/Extra/MultiSet.hs view
@@ -0,0 +1,280 @@+{-# LANGUAGE RecordWildCards #-}++-- | A fast, mutable multiset for `Int` keys backed by a @HashMap@. Most operations are performed+-- in \(O(1)\) time, but in average.+--+-- ==== Invariant+-- The count for each key must be non-negative. An exception is thrown if this invariant is+-- violated.+--+-- ==== Capacity limitation+-- The maximum number of distinct keys that can be inserted is fixed at \(n\), even if some keys are+-- deleted. This is due to the limitation of the internal @HashMap@.+--+-- ==== __Example__+-- Create a `MultiSet` with capacity \(4\):+--+-- >>> import AtCoder.Extra.MultiSet qualified as MS+-- >>> ms <- MS.new 4+--+-- `inc` and `dec` are the primary API:+--+-- >>> MS.inc ms 10+-- >>> MS.inc ms 10+-- >>> MS.lookup ms 10+-- Just 2+--+-- >>> MS.dec ms 10+-- >>> MS.lookup ms 10+-- Just 1+--+-- Entries with zero count are considered to be non-existing:+--+-- >>> MS.dec ms 10+-- >>> MS.member ms 10+-- False+--+-- >>> MS.lookup ms 10+-- Nothing+--+-- >>> MS.size ms+-- 0+--+-- Creating a negative count results in an exception:+--+-- >>> MS.inc ms 11+-- >>> MS.sub ms 11 2+-- *** Exception: AtCoder.Extra.Multiset.sub: the count of `11` is becoming a negative value: `-1`+-- ...+--+-- Decrementing a non-existing key does nothing and does not throw an exception:+--+-- >>> MS.dec ms 12+--+-- Misc:+--+-- >>> MS.insert ms 12 112+-- >>> MS.assocs ms+-- [(11,1),(12,112)]+--+-- @since 1.1.0.0+module AtCoder.Extra.MultiSet+ ( -- * MultiSet+ MultiSet,++ -- * Construtors+ new,++ -- * Metadata+ capacity,+ size,++ -- * Lookups+ lookup,+ member,+ notMember,++ -- * Modifications+ inc,+ dec,+ add,+ sub,+ insert,+ delete,++ -- * Conversions++ -- ** Safe conversions+ keys,+ elems,+ assocs,++ -- ** Unsafe conversions+ unsafeKeys,+ unsafeElems,+ unsafeAssocs,+ )+where++import AtCoder.Extra.HashMap qualified as HM+import Control.Monad (when)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Functor ((<&>))+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 (lookup)++-- | A fast, mutable multiset for `Int` keys backed by a @HashMap@.+--+-- @since 1.1.0.0+data MultiSet s = MultiSet+ { mapMS :: !(HM.HashMap s Int),+ cntMS :: !(VUM.MVector s Int)+ }++-- | \(O(n)\) Creates a `MultiSet` with capacity \(n\).+--+-- @since 1.1.0.0+new :: (PrimMonad m) => Int -> m (MultiSet (PrimState m))+new n = do+ mapMS <- HM.new n+ cntMS <- VUM.replicate 1 0+ pure $ MultiSet {..}++-- | \(O(1)\) Returns the maximum number of distinct keys that can be inserted into the internal+-- hash map.+--+-- @since 1.1.0.0+capacity :: MultiSet s -> Int+capacity = HM.capacity . mapMS++-- | \(O(1)\) Returns the number of distinct keys with positive counts.+--+-- @since 1.1.0.0+size :: (PrimMonad m) => MultiSet (PrimState m) -> m Int+size MultiSet {..} = do+ VGM.unsafeRead cntMS 0++-- | \(O(1)\) Looks up the count for a key.+--+-- @since 1.1.0.0+lookup :: (PrimMonad m) => MultiSet (PrimState m) -> Int -> m (Maybe Int)+lookup MultiSet {..} k = do+ HM.lookup mapMS k <&> \case+ Just i | i > 0 -> Just i+ _ -> Nothing++-- | \(O(1)\) Tests whether \(k\) is in the set.+--+-- @since 1.1.0.0+member :: (PrimMonad m) => MultiSet (PrimState m) -> Int -> m Bool+member MultiSet {..} k = do+ HM.lookup mapMS k <&> \case+ Just i -> i > 0+ _ -> False++-- | \(O(1)\) Tests whether \(k\) is not in the set.+--+-- @since 1.1.0.0+notMember :: (PrimMonad m) => MultiSet (PrimState m) -> Int -> m Bool+notMember ms k = not <$> member ms k++-- | \(O(1)\) Increments the count of a key.+--+-- @since 1.1.0.0+inc :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> m ()+inc ms k = add ms k 1++-- | \(O(1)\) Decrements the count of a key.+--+-- @since 1.1.0.0+dec :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> m ()+dec ms k = sub ms k 1++-- | \(O(1)\) Increments the count of a key \(k\) by \(c\). If the key does not exist in the set,+-- the \((k, c)\) pair is inserted. If \(v\) is negative, it falls back to `sub`.+--+-- @since 1.1.0.0+add :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> Int -> m ()+add ms@MultiSet {..} k v = case compare v 0 of+ LT -> sub ms k (-v)+ EQ -> pure ()+ GT -> do+ HM.lookup mapMS k >>= \case+ Just n -> do+ HM.insert mapMS k $ n + v+ when (n <= 0) $ do+ VGM.unsafeModify cntMS (+ 1) 0+ Nothing -> do+ HM.insert mapMS k v+ VGM.unsafeModify cntMS (+ 1) 0++-- | \(O(1)\) Decrements the count of a key \(k\) by \(c\). If \(c\) is negative, it falls back to+-- `add`.+--+-- @since 1.1.0.0+sub :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> Int -> m ()+sub ms@MultiSet {..} k v = case compare v 0 of+ LT -> add ms k (-v)+ EQ -> pure ()+ GT -> do+ HM.lookup mapMS k >>= \case+ Just 0 -> pure () -- ignored+ Just n -> case compare n v of+ GT -> do+ HM.insert mapMS k (n - v)+ EQ -> do+ HM.insert mapMS k 0+ VGM.unsafeModify cntMS (subtract 1) 0+ LT -> error $ "AtCoder.Extra.Multiset.sub: the count of `" ++ show k ++ "` is becoming a negative value: `" ++ show (n - v) ++ "`"+ _ -> pure ()++-- | \(O(1)\) Inserts a key-count pair into the set. `MultiSet` is actually a count map.+--+-- @since 1.1.0.0+insert :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> Int -> m ()+insert MultiSet {..} k v+ | v <= 0 = error $ "AtCoder.Extra.Multiset.insert: new count must be positive`" ++ show k ++ "`: `" ++ show v ++ "`"+ | otherwise = do+ HM.lookup mapMS k >>= \case+ Just n | n > 0 -> do+ HM.insert mapMS k v+ _ -> do+ HM.insert mapMS k v+ VGM.unsafeModify cntMS (+ 1) 0++-- | \(O(1)\) Deletes a key. Note that it does not undo its insertion and does not increase the+-- number of distinct keys that can be inserted into the internal hash map.+--+-- @since 1.1.0.0+delete :: (HasCallStack, PrimMonad m) => MultiSet (PrimState m) -> Int -> m ()+delete MultiSet {..} k = do+ HM.lookup mapMS k >>= \case+ Just i | i > 0 -> do+ HM.insert mapMS k 0+ VGM.unsafeModify cntMS (subtract 1) 0+ _ -> pure ()++-- | \(O(n)\) Enumerates the keys in the set.+--+-- @since 1.1.0.0+{-# INLINE keys #-}+keys :: (PrimMonad m) => MultiSet (PrimState m) -> m (VU.Vector Int)+keys ms = VU.force <$> unsafeKeys ms++-- | \(O(n)\) Enumerates the counts in the set.+--+-- @since 1.1.0.0+{-# INLINE elems #-}+elems :: (PrimMonad m) => MultiSet (PrimState m) -> m (VU.Vector Int)+elems ms = VU.force <$> unsafeElems ms++-- | \(O(n)\) Enumerates the key-count pairs in the set.+--+-- @since 1.1.0.0+{-# INLINE assocs #-}+assocs :: (PrimMonad m) => MultiSet (PrimState m) -> m (VU.Vector (Int, Int))+assocs ms = VU.force <$> unsafeAssocs ms++-- | \(O(n)\) Enumerates the keys in the set.+--+-- @since 1.1.0.0+{-# INLINE unsafeKeys #-}+unsafeKeys :: (PrimMonad m) => MultiSet (PrimState m) -> m (VU.Vector Int)+unsafeKeys = (VU.mapMaybe (\(!k, !n) -> if n > 0 then Just k else Nothing) <$>) . HM.unsafeAssocs . mapMS++-- | \(O(n)\) Enumerates the counts in the set.+--+-- @since 1.1.0.0+{-# INLINE unsafeElems #-}+unsafeElems :: (PrimMonad m) => MultiSet (PrimState m) -> m (VU.Vector Int)+unsafeElems = (VU.filter (> 0) <$>) . HM.unsafeElems . mapMS++-- | \(O(n)\) Enumerates the key-count pairs in the set.+--+-- @since 1.1.0.0+{-# INLINE unsafeAssocs #-}+unsafeAssocs :: (PrimMonad m) => MultiSet (PrimState m) -> m (VU.Vector (Int, Int))+unsafeAssocs = (VU.filter (\(!_, !n) -> n > 0) <$>) . HM.unsafeAssocs . mapMS
+ src/AtCoder/Extra/Pdsu.hs view
@@ -0,0 +1,306 @@+{-# LANGUAGE RecordWildCards #-}++-- original implementation:+-- <https://qiita.com/drken/items/cce6fc5c579051e64fab>++-- | A potentialized disjoint set union on a [group](https://en.wikipedia.org/wiki/Group_(mathematics\))+-- under a differential constraint system. Each vertex \(v\) is assigned a potential value \(p(v)\),+-- where representatives (`leader`) of each group have a potential of `mempty`, and other vertices have+-- potentials relative to their representative.+--+-- The group type is represented as a `Monoid` with a inverse operator, passed on `new`. This+-- approach avoids defining a separate typeclass for groups.+--+-- ==== Invariant+-- New monoids always come from the left: @new <> old@. The order is important for non-commutative+-- monoid implementations.+--+-- @since 1.1.0.0+module AtCoder.Extra.Pdsu+ ( -- * Pdsu+ Pdsu (nPdsu),++ -- * Constructors+ new,++ -- * Inspection+ leader,+ pot,+ diff,+ unsafeDiff,+ same,+ canMerge,++ -- * Merging+ merge,+ merge_,++ -- * Group information+ size,+ groups,++ -- * Reset+ clear,+ )+where++import AtCoder.Internal.Assert qualified as ACIA+import Control.Monad+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Vector qualified as V+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)++-- | A potentialized disjoint set union on a [group](https://en.wikipedia.org/wiki/Group_(mathematics\))+-- under a differential constraint system. Each vertex \(v\) is assigned a potential value \(p(v)\),+--+-- ==== __Example__+-- Create a `Pdsu` with four vertices with potential type @Sum Int@. Use `negate` as the inverse+-- operator:+--+-- >>> import AtCoder.Extra.Pdsu qualified as Pdsu+-- >>> import Data.Semigroup (Sum (..))+-- >>> dsu <- Pdsu.new @_ @(Sum Int) 4 negate+--+-- The API is similar to @Dsu@, but with differential potential values:+--+-- >>> Pdsu.merge dsu 1 0 (Sum 1) -- p(1) - p(0) := Sum 1+-- True+--+-- >>> Pdsu.merge_ dsu 2 0 (Sum 2) -- p(2) - p(0) := Sum 2+-- >>> Pdsu.leader dsu 0+-- 0+--+-- Potential values can be retrieved with `pot`:+--+-- >>> Pdsu.pot dsu 0+-- Sum {getSum = 0}+--+-- >>> Pdsu.pot dsu 1+-- Sum {getSum = 1}+--+-- >>> Pdsu.pot dsu 2+-- Sum {getSum = 2}+--+-- Difference of potentials in the same group can be retrieved with `diff`:+--+-- >>> Pdsu.diff dsu 2 1+-- Just (Sum {getSum = 1})+--+-- >>> Pdsu.diff dsu 2 3+-- Nothing+--+-- Retrieve group information with `groups`+--+-- >>> Pdsu.groups dsu+-- [[2,1,0],[3]]+--+-- @since 1.1.0.0+data Pdsu s a = Pdsu+ { -- | The number of vertices.+ nPdsu :: {-# UNPACK #-} !Int,+ -- | Parent: non-positive, size: positive+ parentOrSizePdsu :: !(VUM.MVector s Int),+ -- | Diffierencial potential of each vertex.+ potentialPdsu :: !(VUM.MVector s a),+ invertPdsu :: !(a -> a)+ }++-- | \(O(n)\) Creates a new DSU under a differential constraint system.+--+-- @since 1.1.0.0+{-# INLINE new #-}+new ::+ forall m a.+ (PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | The number of vertices+ Int ->+ -- | The inverse operator of the monoid+ (a -> a) ->+ -- | A DSU+ m (Pdsu (PrimState m) a)+new n f = Pdsu n <$> VUM.replicate n (-1 {- size 1 -}) <*> VUM.replicate n (mempty :: a) <*> pure f++-- | \(O(\alpha(n))\) Returns the representative of the connected component that contains the+-- vertex.+--+-- @since 1.1.0.0+{-# INLINE leader #-}+leader :: (HasCallStack, PrimMonad m, Semigroup a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> m Int+leader Pdsu {..} v0 = inner v0+ where+ !_ = ACIA.checkIndex "AtCoder.Extra.Pdsu.leader" v0 nPdsu+ inner v = do+ p <- VGM.read parentOrSizePdsu v+ if {- size? -} p < 0+ then pure v+ else do+ -- NOTE(perf): Path compression.+ -- Handle the nodes closer to the root first and move them onto just under the root+ !r <- inner p+ when (p /= r) $ do+ !pp <- VGM.read potentialPdsu p+ -- Move `v` to just under the root:+ VGM.write parentOrSizePdsu v {- root -} r+ -- INVARIANT: new coming monoids always come from the left. And we're performing+ -- reverse folding.+ VGM.modify potentialPdsu (<> pp) v+ pure r++-- | \(O(\alpha(n))\) Returns \(p(v)\), the potential value of vertex \(v\) relative to the+-- reprensetative of its group.+--+-- @since 1.1.0.0+{-# INLINE pot #-}+pot :: (HasCallStack, PrimMonad m, Semigroup a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> m a+pot dsu@Pdsu {..} v1 = do+ -- Perform path compression+ _ <- leader dsu v1+ VGM.read potentialPdsu v1+ where+ !_ = ACIA.checkIndex "AtCoder.Extra.Pdsu.pot" v1 nPdsu++-- | \(O(\alpha(n))\) Returns whether the vertices \(a\) and \(b\) are in the same connected+-- component.+--+-- @since 1.1.0.0+{-# INLINE same #-}+same :: (HasCallStack, PrimMonad m, Semigroup a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> m Bool+same !dsu !v1 !v2 = (==) <$> leader dsu v1 <*> leader dsu v2++-- TODO: call it unsafeDiff++-- | \(O(\alpha(n))\) Returns the potential of \(v_1\) relative to \(v_2\): \(p(v_1) \cdot p^{-1}(v_2)\)+-- if the two vertices belong to the same group. Returns `Nothing` when the two vertices are not+-- connected.+--+-- @since 1.1.0.0+{-# INLINE diff #-}+diff :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> m (Maybe a)+diff !dsu !v1 !v2 = do+ b <- same dsu v1 v2+ if b+ then Just <$> unsafeDiff dsu v1 v2+ else pure Nothing++-- | \(O(\alpha(n))\) Returns the potential of \(v_1\) relative to \(v_2\): \(p(v_1) \cdot p^{-1}(v_2)\)+-- if the two vertices belong to the same group. Returns meaningless value if the two vertices are+-- not connected.+--+-- @since 1.1.0.0+{-# INLINE unsafeDiff #-}+unsafeDiff :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> m a+unsafeDiff !dsu !v1 !v2 = do+ p1 <- pot dsu v1+ p2 <- pot dsu v2+ pure $ p1 <> invertPdsu dsu p2++-- | \(O(\alpha(n))\) Merges \(v_1\) to \(v_2\) with differential (relative) potential+-- \(\mathrm{dp}\): \(p(v1) := \mathrm{dp} \cdot p(v2)\). Returns `True` if they're newly merged.+--+-- @since 1.1.0.0+{-# INLINE merge #-}+merge :: (HasCallStack, PrimMonad m, Monoid a, Ord a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> a -> m Bool+merge dsu@Pdsu {..} v10 v20 !dp0 = inner v10 v20 dp0+ where+ !_ = ACIA.checkIndex "AtCoder.Extra.Pdsu.merge" v10 nPdsu+ !_ = ACIA.checkIndex "AtCoder.Extra.Pdsu.merge" v20 nPdsu+ inner v1 v2 !dp = do+ !r1 <- leader dsu v1+ !r2 <- leader dsu v2+ if r1 == r2+ then pure False+ else do+ -- NOTE(perf): Union by size (choose smaller one for root).+ -- Another, more proper optimization would be union by rank (depth).+ !size1 <- VGM.read potentialPdsu v1+ !size2 <- VGM.read potentialPdsu v2+ if size1 >= size2+ then do+ -- Merge `r1` onto `r2`++ -- Update the size of `r1`+ !negativeSize1 <- negate {- retrieve size -} <$> VGM.read parentOrSizePdsu r1+ !negativeSize2 <- negate {- retrieve size -} <$> VGM.read parentOrSizePdsu r2+ VGM.write parentOrSizePdsu r1 ({- size -} negativeSize1 + negativeSize2)++ -- p(v1) becomes p'(v1) under r2 after merge. p(r1) becomes p'(r1).+ -- p'(v1) = dp <> p(v2)+ -- p'(v1) = p(v1) <> 'p(r1)+ -- Therefore,+ -- p'(r1) = p^{-1}(v1) <> dp <> p(v2)+ !p1 <- VGM.read potentialPdsu v1+ !p2 <- VGM.read potentialPdsu v2+ let !pr1' = invertPdsu p1 <> dp <> p2++ -- Move `r1` to just under `r2`:+ VGM.write parentOrSizePdsu r1 {- record new root -} r2+ VGM.write potentialPdsu r1 pr1'++ pure True+ else do+ inner v2 v1 $ invertPdsu dp++-- | \(O(\alpha(n))\) `merge` with the return value discarded.+--+-- @since 1.1.0.0+{-# INLINE merge_ #-}+merge_ :: (HasCallStack, PrimMonad m, Monoid a, Ord a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> a -> m ()+merge_ !dsu !v1 !v2 !dp = do+ _ <- merge dsu v1 v2 dp+ pure ()++-- | \(O(\alpha(n))\) Returns `True` if the two vertices belong to different groups or they belong+-- to the same group under the condition \(p(v_1) = dp \cdot p(v_2)\). It's just a convenient+-- helper function.+--+-- @since 1.1.0.0+{-# INLINE canMerge #-}+canMerge :: (HasCallStack, PrimMonad m, Semigroup a, Eq a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> Int -> a -> m Bool+canMerge !dsu !v1 !v2 !dp = do+ b <- same dsu v1 v2+ if not b+ then pure True+ else do+ !p1 <- VGM.read (potentialPdsu dsu) v1+ !p2 <- VGM.read (potentialPdsu dsu) v2+ pure $ p1 == dp <> p2++-- | \(O(\alpha(n))\) Returns the number of vertices belonging to the same group.+--+-- @since 1.1.0.0+{-# INLINE size #-}+size :: (HasCallStack, PrimMonad m, Semigroup a, VU.Unbox a) => Pdsu (PrimState m) a -> Int -> m Int+size !dsu !v = (negate <$>) . VGM.read (parentOrSizePdsu dsu) =<< leader dsu v++-- | \(O(n)\) Divides the graph into connected components and returns the list of them.+--+-- @since 1.1.0.0+{-# INLINE groups #-}+groups :: (PrimMonad m, Semigroup a, VU.Unbox a) => Pdsu (PrimState m) a -> m (V.Vector (VU.Vector Int))+groups dsu@Pdsu {..} = do+ groupSize <- VUM.replicate nPdsu (0 :: Int)+ leaders <- VU.generateM nPdsu $ \i -> do+ li <- leader dsu i+ VGM.modify groupSize (+ 1) li+ pure li+ result <- do+ groupSize' <- VU.unsafeFreeze groupSize+ V.mapM VUM.unsafeNew $ VU.convert groupSize'+ VU.iforM_ leaders $ \i li -> do+ i' <- subtract 1 <$> VGM.read groupSize li+ VGM.write (result VG.! li) i' i+ VGM.write groupSize li i'+ V.filter (not . VU.null) <$> V.mapM VU.unsafeFreeze result++-- | \(O(n)\) Clears the `Pdsu` to the initial state.+--+-- @since 1.1.0.0+{-# INLINE clear #-}+clear :: forall m a. (PrimMonad m, Monoid a, VU.Unbox a) => Pdsu (PrimState m) a -> m ()+clear !dsu = do+ VGM.set (potentialPdsu dsu) (mempty @a)+ VGM.set (parentOrSizePdsu dsu) (-1 {- size -})
+ src/AtCoder/Extra/Semigroup/Matrix.hs view
@@ -0,0 +1,264 @@+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE RecordWildCards #-}++-- | A simple HxW matrix backed by a vector, mainly for binary exponention.+--+-- The matrix is a left semigroup action: \(m_2 (m_1 v) = (m_2 \circ m_1) v\).+--+-- @since 1.1.0.0+module AtCoder.Extra.Semigroup.Matrix+ ( -- * Matrix+ Matrix (..),++ -- * Constructors+ new,+ zero,+ ident,+ diag,++ -- * Mapping+ map,++ -- * Multiplications+ mulToCol,+ mul,+ mulMod,+ mulMint,++ -- * Powers+ pow,+ powMod,+ powMint,+ )+where++import AtCoder.Extra.Math qualified as ACEM+import AtCoder.Internal.Assert qualified as ACIA+import AtCoder.Internal.Barrett qualified as BT+import AtCoder.ModInt qualified as M+import Data.Foldable (for_)+import Data.Semigroup (Semigroup (..))+import Data.Vector qualified as V+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.Exts (proxy#)+import GHC.Stack (HasCallStack)+import GHC.TypeNats (KnownNat, natVal')+import Prelude hiding (map)++-- | A simple HxW matrix backed by a vector, mainly for binary exponention.+--+-- The matrix is a left semigroup action: \(m_2 (m_1 v) = (m_2 \circ m_1) v\).+--+--+-- @since 1.1.0.0+data Matrix a = Matrix+ { -- | @since 1.1.0.0+ hM :: {-# UNPACK #-} !Int,+ -- | @since 1.1.0.0+ wM :: {-# UNPACK #-} !Int,+ -- | @since 1.1.0.0+ vecM :: !(VU.Vector a)+ }+ deriving+ ( -- | @since 1.1.0.0+ Show,+ -- | @since 1.1.0.0+ Eq+ )++-- | Type alias of a column vector.+--+-- @since 1.1.0.0+type Col a = VU.Vector a++-- | \(O(hw)\) Creates an HxW matrix.+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (HasCallStack, VU.Unbox a) => Int -> Int -> VU.Vector a -> Matrix a+new h w vec+ | VU.length vec /= h * w = error "AtCoder.Extra.Matrix: size mismatch"+ | otherwise = Matrix h w vec++-- | \(O(n^2)\) Creates an NxN zero matrix.+--+-- @since 1.1.0.0+{-# INLINE zero #-}+zero :: (VU.Unbox a, Num a) => Int -> Matrix a+zero n = Matrix n n $ VU.replicate (n * n) 0++-- | \(O(n^2)\) Creates an NxN identity matrix.+--+-- @since 1.1.0.0+{-# INLINE ident #-}+ident :: (VU.Unbox a, Num a) => Int -> Matrix a+ident n = Matrix n n $ VU.create $ do+ vec <- VUM.replicate (n * n) 0+ for_ [0 .. n - 1] $ \i -> do+ VGM.write vec (i + n * i) 1+ pure vec++-- | \(O(n^2)\) Creates an NxN diagonal matrix.+--+-- @since 1.1.0.0+{-# INLINE diag #-}+diag :: (VU.Unbox a, Num a) => Int -> VU.Vector a -> Matrix a+diag n xs = Matrix n n $ VU.create $ do+ vec <- VUM.replicate (n * n) 0+ VU.iforM_ xs $ \i x -> do+ VGM.write vec (i + n * i) x+ pure vec++-- | \(O(n^2)\) Maps the `Matrix`.+--+-- @since 1.1.0.0+{-# INLINE map #-}+map :: (VU.Unbox a, VU.Unbox b) => (a -> b) -> Matrix a -> Matrix b+map f Matrix {..} = Matrix hM wM $ VU.map f vecM++-- | \(O(hw)\) Multiplies HxW matrix to a Hx1 column vector.+--+-- @since 1.1.0.0+{-# INLINE mulToCol #-}+mulToCol :: (Num a, VU.Unbox a) => Matrix a -> Col a -> Col a+mulToCol Matrix {..} !col = VU.convert $ V.map (VU.sum . VU.zipWith (*) col) rows+ where+ !n = VU.length col+ !_ = ACIA.runtimeAssert (n == wM) "AtCoder.Extra.Matrix.mulToCol: size mismatch"+ rows = V.unfoldrExactN hM (VU.splitAt wM) vecM++-- | \(O(h_1 K w_2)\) Multiplies H1xK matrix to a KxW2 matrix.+--+-- @since 1.1.0.0+{-# INLINE mul #-}+mul :: (Num e, VU.Unbox e) => Matrix e -> Matrix e -> Matrix e+mul !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f row col = VU.sum $ VU.imap (\iRow x -> x * VG.unsafeIndex vecB (col + iRow * w')) (VU.unsafeSlice (w * row) w vecA)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mul: matrix size mismatch"++-- | \(O(h_1 w_2 K)\) Multiplies H1xK matrix to a KxW2 matrix, taking the mod.+--+-- @since 1.1.0.0+{-# INLINE mulMod #-}+mulMod :: Int -> Matrix Int -> Matrix Int -> Matrix Int+mulMod !m !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ !bt = BT.new32 $ fromIntegral m+ f row col = VU.foldl1' addMod $ VU.imap (\iRow x -> mulMod_ x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ addMod x y = (x + y) `rem` m+ mulMod_ x y = fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mulMod: matrix size mismatch"++-- | \(O(h_1 w_2 K)\) `mul` specialized to `M.ModInt`.+--+-- @since 1.1.0.0+{-# INLINE mulMint #-}+mulMint :: forall a. (KnownNat a) => Matrix (M.ModInt a) -> Matrix (M.ModInt a) -> Matrix (M.ModInt a)+mulMint = mulMintImpl bt+ where+ !bt = BT.new32 $ fromIntegral (natVal' (proxy# @a))++{-# INLINE mulMintImpl #-}+mulMintImpl :: forall a. (KnownNat a) => BT.Barrett -> Matrix (M.ModInt a) -> Matrix (M.ModInt a) -> Matrix (M.ModInt a)+mulMintImpl !bt !a !b =+ Matrix h w' $+ VU.unfoldrExactN+ (h * w')+ ( \(!row, !col) ->+ let !x = f row col+ in if col + 1 >= w'+ then (x, (row + 1, 0))+ else (x, (row, col + 1))+ )+ (0, 0)+ where+ f :: Int -> Int -> M.ModInt a+ f row col = VU.sum $ VU.imap (\iRow x -> mulMod_ x (VG.unsafeIndex vecB (col + (iRow * w')))) (VU.unsafeSlice (w * row) w vecA)+ mulMod_ :: M.ModInt a -> M.ModInt a -> M.ModInt a+ mulMod_ (M.ModInt x) (M.ModInt y) = M.unsafeNew . fromIntegral $ BT.mulMod bt (fromIntegral x) (fromIntegral y)+ h = hM a+ w = wM a+ h' = hM b+ vecA = vecM a+ w' = wM b+ vecB = vecM b+ !_ = ACIA.runtimeAssert (w == h') "AtCoder.Extra.Matrix.mulMint: matrix size mismatch"++-- | \(O(w n^3)\) Calculates \(M^k\).+--+-- @since 1.1.0.0+{-# INLINE pow #-}+pow :: Int -> Matrix Int -> Matrix Int+pow k mat+ | k < 0 = error "AtCoder.Extra.Matrix.powMod: the exponential must be non-negative"+ | k == 0 = ident $ hM mat+ | otherwise = ACEM.power mul k mat+ where+ !_ = ACIA.runtimeAssert (hM mat == wM mat) "AtCoder.Extra.Matrix.powMod: matrix size mismatch"++-- | \(O(w n^3)\) Calculates \(M^k\), taking the mod.+--+-- @since 1.1.0.0+{-# INLINE powMod #-}+powMod :: Int -> Int -> Matrix Int -> Matrix Int+powMod m k mat+ | k < 0 = error "AtCoder.Extra.Matrix.powMod: the exponential must be non-negative"+ | k == 0 = ident $ hM mat+ | otherwise = ACEM.power (mulMod m) k mat+ where+ !_ = ACIA.runtimeAssert (hM mat == wM mat) "AtCoder.Extra.Matrix.powMod: matrix size mismatch"++-- | \(O(w n^3)\) Calculates \(M^k\), specialized to `M.ModInt`.+--+-- @since 1.1.0.0+powMint :: forall m. (KnownNat m) => Int -> Matrix (M.ModInt m) -> Matrix (M.ModInt m)+powMint k mat+ | k < 0 = error "AtCoder.Extra.Matrix.powMint: the exponential must be non-negative"+ | k == 0 = ident $ hM mat+ | otherwise = ACEM.power (mulMintImpl bt) k mat+ where+ !_ = ACIA.runtimeAssert (hM mat == wM mat) "AtCoder.Extra.Matrix.powMint: matrix size mismatch"+ !bt = BT.new32 $ fromIntegral (natVal' (proxy# @m))++-- | @since 1.1.0.0+instance (Num a, VU.Unbox a) => Semigroup (Matrix a) where+ {-# INLINE (<>) #-}+ (<>) = mul+ {-# INLINE stimes #-}+ stimes = ACEM.power (<>) . fromIntegral
+ src/AtCoder/Extra/Semigroup/Permutation.hs view
@@ -0,0 +1,114 @@+-- | A permutation represented by a vector, mainly for binary exponentiation.+--+-- The permutation is a left semigroup action: \(p_2 (p_1 x) = (p_2 \circ p_1) x\).+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Semigroup.Permutation qualified as Permutation+-- >>> import Data.Semigroup (Semigroup (stimes))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let perm = Permutation.new $ VU.fromList [1, 2, 3, 0]+-- >>> Permutation.act perm 1+-- 2+--+-- >>> Permutation.act (perm <> perm) 1+-- 3+--+-- >>> Permutation.act (stimes 3 perm) 1+-- 0+--+-- @since 1.1.0.0+module AtCoder.Extra.Semigroup.Permutation+ ( -- * Permutation+ Permutation (..),++ -- * Constructors+ new,+ unsafeNew,+ ident,+ zero,++ -- * Actions+ act,++ -- * Metadata+ length,+ )+where++import AtCoder.Internal.Assert qualified as ACIA+import Data.Vector.Generic qualified as VG+import Data.Vector.Unboxed qualified as VU+import GHC.Stack (HasCallStack)+import Prelude hiding (length)++-- | A permutation represented by a vector, mainly for binary exponentiation.+--+-- The permutation is a left semigroup action: \(p_2 (p_1 x) = (p_2 \circ p_1) x\).+--+-- @since 1.1.0.0+newtype Permutation = Permutation+ { unPermutation :: VU.Vector Int+ }+ deriving newtype+ ( -- | @since 1.1.0.0+ Eq,+ -- | @since 1.1.0.0+ Show+ )++-- | \(O(1)\) Creates a `Permutation`, performing boundary check on input vector.+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: (HasCallStack) => VU.Vector Int -> Permutation+new xs = Permutation xs+ where+ n = VU.length xs+ !_ = VU.foldl' (\() i -> let !_ = ACIA.runtimeAssert (-1 <= i && i < n) "AtCoder.Extra.Semigroup.Permutation.new: index boundary error" in ()) () xs++-- | \(O(1)\) Creates a `Permutation`, without performing boundary check on input vector.+--+-- @since 1.1.0.0+{-# INLINE unsafeNew #-}+unsafeNew :: (HasCallStack) => VU.Vector Int -> Permutation+unsafeNew = Permutation++-- | \(O(1)\) Creates an identity `Permutation` of length \(n\).+--+-- @since 1.1.0.0+{-# INLINE ident #-}+ident :: Int -> Permutation+ident = Permutation . (`VU.generate` id)++-- | \(O(1)\) Creates a zero `Permutation` of length \(n\). It's similar to `ident`, but filled+-- with \(-1\) and invalidates corresponding slots on composition.+--+-- @since 1.1.0.0+{-# INLINE zero #-}+zero :: Int -> Permutation+zero n = Permutation $ VU.replicate n (-1)++-- | \(O(1)\) Maps an index.+--+-- @since 1.1.0.0+{-# INLINE act #-}+act :: (HasCallStack) => Permutation -> Int -> Int+act (Permutation vec) i = case vec VG.! i of+ (-1) -> i+ i' -> i'++-- | \(O(1)\) Returns the length of the internal vector.+--+-- @since 1.1.0.0+{-# INLINE length #-}+length :: (HasCallStack) => Permutation -> Int+length = VU.length . unPermutation++-- | @since 1.1.0.0+instance Semigroup Permutation where+ {-# INLINE (<>) #-}+ Permutation r2 <> Permutation r1 = Permutation $ VU.map f r1+ where+ !_ = ACIA.runtimeAssert (VU.length r2 == VU.length r1) "AtCoder.Extra.Semigroup.Permutation.(<>): legth mismatch"+ f (-1) = -1+ f i = VG.unsafeIndex r2 i
+ src/AtCoder/Extra/Tree.hs view
@@ -0,0 +1,207 @@+-- | Generic tree functions.+--+-- @since 1.1.0.0+module AtCoder.Extra.Tree+ ( -- * Tree folding++ -- | These function are built around the three type parameters: \(w\), \(f\) and \(a\).+ --+ -- - \(w\): Edge weight.+ -- - \(f\): Monoid action to a vertex value. These actions are created from vertex value \(a\)+ -- and edge information @(Int, w)@.+ -- - \(a\): Monoid values stored at vertices.+ fold,+ scan,+ foldReroot,+ )+where++import Data.Functor.Identity (runIdentity)+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)++{-# INLINE foldImpl #-}+foldImpl ::+ forall m w f a.+ (HasCallStack, Monad m, VU.Unbox w) =>+ (Int -> VU.Vector (Int, w)) ->+ (Int -> a) ->+ (a -> (Int, w) -> f) ->+ (f -> a -> a) ->+ Int ->+ (Int -> a -> m ()) ->+ m a+foldImpl tree valAt toF act root memo = inner (-1) root+ where+ inner :: Int -> Int -> m a+ inner !parent !v1 = do+ let !acc0 = valAt v1+ let !v2s = VU.filter ((/= parent) . fst) $ tree v1+ !res <- VU.foldM' (\acc (!v2, !w) -> (`act` acc) . (`toF` (v1, w)) <$> inner v1 v2) acc0 v2s+ memo v1 res+ pure res++-- | \(O(n)\) Folds a tree from a root vertex, also known as tree DP.+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import AtCoder.Extra.Tree qualified as Tree+-- >>> import Data.Semigroup (Sum (..))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let gr = Gr.build @(Sum Int) 5 . Gr.swapDupe $ VU.fromList [(2, 1, Sum 1), (1, 0, Sum 1), (2, 3, Sum 1), (3, 4, Sum 1)]+-- >>> type W = Sum Int -- edge weight+-- >>> type F = Sum Int -- action type+-- >>> type X = Sum Int -- vertex value+-- >>> :{+-- let res = Tree.fold (gr `Gr.adjW`) valAt toF act 2+-- where+-- valAt :: Int -> X+-- valAt = const $ mempty @(Sum Int)+-- toF :: X -> (Int, W) -> F+-- toF x (!_i, !dx) = x + dx+-- act :: F -> X -> X+-- act dx x = dx + x+-- in getSum res+-- :}+-- 4+--+-- @since 1.1.0.0+{-# INLINE fold #-}+fold ::+ (HasCallStack, VU.Unbox w) =>+ -- | Graph as a function.+ (Int -> VU.Vector (Int, w)) ->+ -- | @valAt@: Assignment of initial vertex values.+ (Int -> a) ->+ -- | @toF@: Converts a vertex value into an action onto a neighbor vertex.+ (a -> (Int, w) -> f) ->+ -- | @act@: Performs an action onto a vertex value.+ (f -> a -> a) ->+ -- | Root vertex.+ Int ->+ -- | Tree folding result from the root vertex.+ a+fold tree valAt toF act root = runIdentity $ do+ foldImpl tree valAt toF act root (\_ _ -> pure ())++-- | \(O(n)\) Folds a tree from a root vertex, also known as tree DP. The calculation process on+-- every vertex is recoreded and returned as a vector.+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import AtCoder.Extra.Tree qualified as Tree+-- >>> import Data.Semigroup (Sum (..))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let n = 5+-- >>> let gr = Gr.build @(Sum Int) n . Gr.swapDupe $ VU.fromList [(2, 1, Sum 1), (1, 0, Sum 1), (2, 3, Sum 1), (3, 4, Sum 1)]+-- >>> type W = Sum Int -- edge weight+-- >>> type F = Sum Int -- action type+-- >>> type X = Sum Int -- vertex value+-- >>> :{+-- let res = Tree.scan n (gr `Gr.adjW`) valAt toF act 2+-- where+-- valAt :: Int -> X+-- valAt = const $ mempty @(Sum Int)+-- toF :: X -> (Int, W) -> F+-- toF x (!_i, !dx) = x + dx+-- act :: F -> X -> X+-- act dx x = dx + x+-- in VU.map getSum res+-- :}+-- [0,1,4,1,0]+--+-- @since 1.1.0.0+{-# INLINE scan #-}+scan ::+ (VU.Unbox w, VG.Vector v a) =>+ -- | The number of vertices.+ Int ->+ -- | Graph as a function.+ (Int -> VU.Vector (Int, w)) ->+ -- | @valAt@: Assignment of initial vertex values.+ (Int -> a) ->+ -- | @toF@: Converts a vertex value into an action onto a neighbor vertex.+ (a -> (Int, w) -> f) ->+ -- | @act@: Performs an action onto a vertex value.+ (f -> a -> a) ->+ -- | Root vertex.+ Int ->+ -- | Tree scanning result from a root vertex.+ v a+scan n tree acc0At toF act root = VG.create $ do+ dp <- VGM.unsafeNew n+ !_ <- foldImpl tree acc0At toF act root $ \v a -> do+ VGM.unsafeWrite dp v a+ pure dp++-- | \(O(n)\) Folds a tree from every vertex, using the rerooting technique.+--+-- ==== __Example__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import AtCoder.Extra.Tree qualified as Tree+-- >>> import Data.Semigroup (Sum (..))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> let n = 5+-- >>> let gr = Gr.build @(Sum Int) n . Gr.swapDupe $ VU.fromList [(2, 1, Sum 1), (1, 0, Sum 1), (2, 3, Sum 1), (3, 4, Sum 1)]+-- >>> type W = Sum Int -- edge weight+-- >>> type F = Sum Int -- action type+-- >>> type X = Sum Int -- vertex value+-- >>> :{+-- let res = Tree.foldReroot n (gr `Gr.adjW`) valAt toF act+-- where+-- valAt :: Int -> X+-- valAt = const $ mempty @(Sum Int)+-- toF :: X -> (Int, W) -> F+-- toF x (!_i, !dx) = x + dx+-- act :: F -> X -> X+-- act dx x = dx + x+-- in VU.map getSum res+-- :}+-- [4,4,4,4,4]+--+-- @since 1.1.0.0+{-# INLINE foldReroot #-}+foldReroot ::+ forall w f a.+ (HasCallStack, VU.Unbox w, VU.Unbox a, VU.Unbox f, Monoid f) =>+ -- | The number of vertices.+ Int ->+ -- | Graph as a function.+ (Int -> VU.Vector (Int, w)) ->+ -- | @valAt@:Assignment of initial vertex values.+ (Int -> a) ->+ -- | @toF@: Converts a vertex value into an action onto a neighbor vertex.+ (a -> (Int, w) -> f) ->+ -- | @act@: Performs an action onto a vertex value.+ (f -> a -> a) ->+ -- | Tree folding result from every vertex as a root.+ VU.Vector a+foldReroot n tree valAt toF act = VU.create $ do+ -- Calculate tree DP for every vertex as a root:+ !dp <- VUM.unsafeNew n+ let reroot parent parentF v1 = do+ -- TODO: when the operator is not commutative?+ let !children = VU.filter ((/= parent) . fst) $ tree v1+ let !fL = VU.scanl' (\ !f (!v2, !w) -> (f <>) . (`toF` (v1, w)) $ treeDp VG.! v2) f0 children+ let !fR = VU.scanr' (\(!v2, !w) !f -> (<> f) . (`toF` (v1, w)) $ treeDp VG.! v2) f0 children++ -- save+ let !x1 = (parentF <> VU.last fL) `act` valAt v1+ VGM.unsafeWrite dp v1 x1++ VU.iforM_ children $ \i2 (!v2, !w) -> do+ -- composited operator excluding @v2@:+ let !f1 = parentF <> (fL VG.! i2) <> (fR VG.! (i2 + 1))+ let !v1Acc = f1 `act` valAt v1+ let !f2 = toF v1Acc (v2, w)+ reroot v1 f2 v2++ reroot (-1 :: Int) f0 root0+ pure dp+ where+ !root0 = 0 :: Int+ !f0 = mempty @f+ !treeDp = scan n tree valAt toF act root0 :: VU.Vector a
+ src/AtCoder/Extra/Tree/Hld.hs view
@@ -0,0 +1,512 @@+{-# LANGUAGE RecordWildCards #-}++-- | Heavy-light decomposition is a method for partitioning a tree into segments with consecutive+-- indices. It processes various path queries in \(O(\log n)\) time. For segment tree integration+-- and monoid products, refer to the @TreeMonoid@ module.+--+-- ==== __Overview of the internals__+-- The following is for understanding the internals, not for using the API. Skip to the examples if+-- you want.+--+-- ===== Original tree+--+-- Consider a tree with arbitrary vertex order:+--+-- @+-- 0--8--7--3--1--2--12--13--15--14 XX: original Vertex+-- | | --: edge+-- 10--5 11--8--6 |: edge+-- |+-- 4+-- @+--+-- ===== `indexHld`: Vertex -> VertexHld+--+-- The tree vertices are reindexed with `indexHld`, where each segment is assigned consecutive+-- vertex indices:+--+-- @+-- 0==1==2==3==4==5==6==7==8==9 XX: VertexHld+-- | | ==: edges on the same semgent+-- 14==13 10==11==12 |: edge between different segments+-- |+-- 15+-- @+--+-- Note that vertices on higher (closer to the root) segments are assigned smaller indices. This is+-- very internally very important when calculating `lca`.+--+-- ===== `headHld`: Vertex -> Vertex+--+-- `headHld` points the "head" vertex of each segment. It can be used for finding LCA of two+-- vertices. To find the LCA, move up to the head, go up to the parental segment's vertex and+-- repeat until the two vertices are on the same segment.+--+-- @+-- 0==0==0==0==0==0==0==0==0==0 XX: original Vertex+-- | |+-- 5==5 11==11==11+-- |+-- 4+-- @+--+-- `headHld` also works for identifying segments. When two vertices are on the same segment, they+-- have the same head.+--+-- ===== `parentHld`: Vertex -> Vertex+--+-- `parentHld` points the parental segment's vertex from a head:+--+-- @+-- (-1)==0==8==7==3==1==2==12==13==15 XX: original Vertex+-- | |+-- 5==8 1==11=8+-- |+-- 5+-- @+--+-- ==== __Example__+-- Create an `Hld` for a tree:+--+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import AtCoder.Extra.Tree.Hld qualified as Hld+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> -- 0--1--2--3+-- >>> -- ++-- >>> -- +--4--5+-- >>> let n = 6+-- >>> let tree = Gr.build' n . Gr.swapDupe' $ VU.fromList [(0, 1), (1, 2), (2, 3), (1, 4), (4, 5)]+-- >>> let hld = Hld.new tree+--+-- `Hld` can process various queries in \(O(\log n)\) time:+--+-- >>> Hld.ancestor hld 5 3 -- go up three parents from `5`+-- 0+--+-- >>> Hld.jump hld 5 2 3 -- go to the third vertex from `5` to `2`:+-- Just 2+--+-- >>> Hld.lengthBetween hld 5 3 -- get the length (the number of edges) between `5` and `3`:+-- 4+--+-- >>> Hld.path hld 5 3 -- get the path between `5` and `3`:+-- [5,4,1,2,3]+--+-- Our `Hld` is rooted at @0@ vertex and subtree queries are available:+--+-- >>> Hld.isInSubtree hld 2 3 -- `3` is in the subtree of `2`+-- True+--+-- >>> Hld.isInSubtree hld 2 4 -- `4` is not in the subtree of `2`+-- False+--+-- ===== Segment queries+-- Products and segment queries are primarily used by the @TreeMonoid@ module and is not intended+-- for diretct use, but here's some examples. This time the reindex by the HLD is identity:+--+-- >>> Hld.indexHld hld+-- [0,1,2,3,4,5]+--+-- So we can easily understand the outputs:+--+-- >>> Hld.pathSegmentsInclusive Hld.WeightsAreOnVertices hld 5 3+-- [(5,4),(1,3)]+--+-- >>> Hld.pathSegmentsInclusive Hld.WeightsAreOnEdges hld 5 3 -- LCA (1) is removed+-- [(5,4),(2,3)]+--+-- >>> Hld.subtreeSegmentInclusive hld 1+-- (1,5)+--+-- @since 1.1.0.0+module AtCoder.Extra.Tree.Hld+ ( -- * Hld+ Hld (..),+ Vertex,+ VertexHld,++ -- * Constructors+ new,+ newAt,++ -- * LCA+ lca,++ -- * Jump+ ancestor,+ jump,++ -- * Path+ lengthBetween,+ path,+ pathSegmentsInclusive,++ -- * Subtree+ subtreeSegmentInclusive,+ isInSubtree,++ -- * Products+ WeightPolicy (..),+ prod,+ )+where++import AtCoder.Extra.Graph qualified as Gr+import AtCoder.Internal.Assert qualified as ACIA+import Control.Monad+import Control.Monad.Fix+import Control.Monad.ST+import Data.Maybe+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)++-- | Original graph vertex.+--+-- @since 1.1.0.0+type Vertex = Int++-- | Vertex reindexed by `indexHld`.+--+-- @since 1.1.0.0+type VertexHld = Vertex++-- | `Hld` partitions a tree into segments and assignes contiguous `VertexHld` for each segment.+--+-- @since 1.1.0.0+data Hld = Hld+ { -- | The root vertex.+ --+ -- @since 1.1.0.0+ rootHld :: {-# UNPACK #-} !Vertex,+ -- | Maps `Vertex` to the parent `Vertex`. Returns @-1@ for the root node.+ --+ -- @since 1.1.0.0+ parentHld :: !(VU.Vector Vertex),+ -- | Maps `Vertex` to `VertexHld`, re-indexed vertices contiguous in each segment.+ --+ -- @since 1.1.0.0+ indexHld :: !(VU.Vector VertexHld),+ -- | Maps `Vertex` to the head `Vertex` of the segment.+ --+ -- @since 1.1.0.0+ headHld :: !(VU.Vector Vertex),+ -- | Maps `VertexHld` back to `Vertex`. Used for `ancestor` etc.+ --+ -- @since 1.1.0.0+ revIndexHld :: !(VU.Vector Vertex),+ -- | Maps `Vertex` to their depth from the root. Used for `jump` etc.+ --+ -- @since 1.1.0.0+ depthHld :: !(VU.Vector Int),+ -- | Maps `Vertex` to the subtree size. This is for subtree products.+ --+ -- @since 1.1.0.0+ subtreeSizeHld :: !(VU.Vector Int)+ }+ deriving+ ( -- | @since 1.1.0.0+ Show,+ -- | @since 1.1.0.0+ Eq+ )++-- | \(O(n)\) Creates an `Hld` with \(0\) as the root vertex.+--+-- @since 1.1.0.0+{-# INLINE new #-}+new :: forall w. (HasCallStack) => Gr.Csr w -> Hld+new tree = newAt tree 0++-- | \(O(n)\) Creates an `Hld` with a root vertex specified.+--+-- @since 1.1.0.0+{-# INLINE newAt #-}+newAt :: forall w. (HasCallStack) => Gr.Csr w -> Vertex -> Hld+newAt tree root = runST $ do+ -- Re-create adjacent vertices so that the biggest subtree's head vertex comes first.+ --+ -- We /could/ instead record the biggest adjacent subtree vertex for each vertex, but the other+ -- DFS would be harder.+ let (!tree', !parent, !depths, !subtreeSize) = runST $ do+ adjVec <- VU.thaw (Gr.adjCsr tree)+ parent_ <- VUM.unsafeNew n+ depths_ <- VUM.unsafeNew n+ subtreeSize_ <- VUM.unsafeNew n++ _ <- (\f -> fix f 0 (-1) root) $ \loop depth p v1 -> do+ VGM.write parent_ v1 p+ VGM.write depths_ v1 depth++ (!size1, !eBig) <-+ VU.foldM'+ ( \(!size1, !eBig) (!e2, !v2) -> do+ if v2 == p+ then pure (size1, eBig)+ else do+ size2 <- loop (depth + 1) v1 v2+ -- NOTE: It's `>` because we should swap at least once if there's some vertex other+ -- that the parent_.+ pure (size1 + size2, if size1 > size2 then eBig else e2)+ )+ (1 :: Int, -1)+ (tree `Gr.eAdj` v1)++ -- move the biggest subtree's head to the first adjacent vertex.+ -- it means the "heavy edge" or the longest segment.+ when (eBig /= -1) $ do+ VGM.swap adjVec eBig $ fst (VG.head (tree `Gr.eAdj` v1))++ -- record subtree size+ VGM.write subtreeSize_ v1 size1++ pure size1++ !vec <- VU.unsafeFreeze adjVec+ (tree {Gr.adjCsr = vec},,,)+ <$> VU.unsafeFreeze parent_+ <*> VU.unsafeFreeze depths_+ <*> VU.unsafeFreeze subtreeSize_++ -- vertex -> reindexed vertex index+ indices <- VUM.replicate n (-1 :: Int)++ -- vertex -> head vertex of the segment+ heads <- VUM.replicate n (-1 :: Int)++ _ <- (\f -> fix f (0 :: Int) root (-1) root) $ \loop acc h p v1 -> do+ -- reindex:+ VGM.write indices v1 acc+ let !acc' = acc + 1++ VGM.write heads v1 h++ -- when the first vertex is within the same segment:+ let (!adj1, !rest) = fromJust $ VU.uncons (tree' `Gr.adj` v1)+ acc'' <-+ if adj1 == p+ then pure acc'+ else loop acc' h v1 adj1++ -- the others are in other segments:+ VU.foldM'+ ( \a v2 -> do+ if v2 == p+ then pure a+ else loop a v2 v1 v2+ )+ acc''+ rest++ !indices' <- VU.unsafeFreeze indices+ let !revIndex = VU.update (VU.replicate n (-1)) $ VU.imap (flip (,)) indices'++ Hld root parent indices'+ <$> VU.unsafeFreeze heads+ <*> pure revIndex+ <*> pure depths+ <*> pure subtreeSize+ where+ !n = Gr.nCsr tree+ !_ = ACIA.runtimeAssert (2 * (Gr.nCsr tree - 1) == Gr.mCsr tree) "AtCoder.Extra.Hld.newAt: not a non-directed tree"++-- | \(O(\log n)\) Calculates the lowest common ancestor of \(u\) and \(v\).+--+-- @since 1.1.0.0+{-# INLINE lca #-}+lca :: (HasCallStack) => Hld -> Vertex -> Vertex -> Vertex+lca Hld {..} = inner+ where+ inner !x !y+ -- sort for easier processing+ -- TODO: @case compare ix iy@ would be easier for me to understand+ | ix > iy = inner y x+ -- @x@ and @y@ are in other segments:+ | hx /= hy = inner x $ parentHld VG.! hy+ -- @x@ and @y@ are within the same segment:+ -- select the smaller one, which is closer to the root and that is the LCA.+ | otherwise = x+ where+ !ix = indexHld VG.! x+ !iy = indexHld VG.! y+ hx = headHld VG.! x+ hy = headHld VG.! y++-- | \(O(\log n)\) Go up \(k\) times from a vertex \(v\) to the root node. Throws an error if \(k\)+-- is bigger than the depth of \(v\).+--+-- @since 1.1.0.0+{-# INLINE ancestor #-}+ancestor :: (HasCallStack) => Hld -> Vertex -> Int -> Vertex+ancestor Hld {..} parent k0 = inner parent k0+ where+ !_ = ACIA.runtimeAssert (0 <= k0 && k0 <= depthHld VG.! parent) $ "AtCoder.Extra.Tree.Hld.ancestor: k-th ancestor is out of the bounds (`k = " ++ show k0 ++ "`)"+ inner v k+ -- on this segment+ | k <= iv - ihv = revIndexHld VG.! (iv - k)+ -- next segment+ | otherwise = inner (parentHld VG.! hv) (k - (iv - ihv + 1))+ where+ iv = indexHld VG.! v+ hv = headHld VG.! v+ ihv = indexHld VG.! hv++-- | \(O(\log n)\) Returns the \(k\)-th vertex of the path between \(u\) and \(v\) from \(u\).+-- Throws an error if `k` is out+--+-- @since 1.1.0.0+{-# INLINE jump #-}+jump :: (HasCallStack) => Hld -> Vertex -> Vertex -> Int -> Maybe Vertex+jump hld@Hld {..} u v k+ | k > lenU + lenV = Nothing+ | k <= lenU = Just $ ancestor hld u k+ | otherwise = Just $ ancestor hld v (lenU + lenV - k)+ where+ lca_ = lca hld u v+ du = depthHld VG.! u+ dv = depthHld VG.! v+ lenU = du - depthHld VG.! lca_+ lenV = dv - depthHld VG.! lca_++-- | \(O(\log n)\) Returns the length of the path between \(u\) and \(v\).+--+-- @since 1.1.0.0+{-# INLINE lengthBetween #-}+lengthBetween :: (HasCallStack) => Hld -> Vertex -> Vertex -> Int+lengthBetween hld@Hld {..} u v = du - dLca + dv - dLca+ where+ !lca_ = lca hld u v+ !dLca = depthHld VG.! lca_+ !du = depthHld VG.! u+ !dv = depthHld VG.! v++-- | \(O(n)\) Returns the vertices on the path between \(u\) and \(v\).+--+-- @since 1.1.0.0+{-# INLINE path #-}+path :: (HasCallStack) => Hld -> Vertex -> Vertex -> [Vertex]+path hld@Hld {..} u v = concatMap expand $ pathSegmentsInclusive WeightsAreOnVertices hld u v+ where+ expand (!l, !r)+ | l <= r = map (revIndexHld VG.!) [l .. r]+ | otherwise = map (revIndexHld VG.!) [l, l - 1 .. r]++-- | \(O(\log n)\) Decomposes a path between two vertices \(u\) and \(v\) into segments. Each+-- segment is represented as an __inclusive__ range \([u_i, v_i]\) of `VertexHLD`.+--+-- The LCA is omitted from the returning vertices when the weight policy is set to+-- `WeightsAreOnEdges`. This is the trick to put edge weights to on vertices.+--+-- @since 1.1.0.0+{-# INLINE pathSegmentsInclusive #-}+pathSegmentsInclusive :: (HasCallStack) => WeightPolicy -> Hld -> Vertex -> Vertex -> [(VertexHld, VertexHld)]+pathSegmentsInclusive weightPolicy Hld {..} x0 y0 = done $ inner x0 [] y0 []+ where+ isEdge = weightPolicy == WeightsAreOnEdges+ done (!up, !down) = reverse up ++ down+ -- @up@: bottom to top. [(max, min)]+ -- @down@: top to bottom. [(min, max)]+ inner :: Vertex -> [(VertexHld, VertexHld)] -> Vertex -> [(VertexHld, VertexHld)] -> ([(VertexHld, VertexHld)], [(VertexHld, VertexHld)])+ inner x up y down+ | hx == hy && isEdge = case compare ix iy of+ -- skip LCA on edge vertices+ LT -> (up, (ix {- edge -} + 1, iy) : down)+ GT -> ((ix, iy {- edge -} + 1) : up, down)+ EQ -> (up, down)+ | hx == hy && not isEdge = case compare ix iy of+ LT -> (up, (ix, iy) : down)+ _ -> ((ix, iy) : up, down)+ | otherwise = case compare ix iy of+ LT -> inner x up phy ((ihy, iy) : down)+ GT -> inner phx ((ix, ihx) : up) y down+ EQ -> error "unreachable"+ where+ ix, iy :: VertexHld+ !ix = indexHld VG.! x+ !iy = indexHld VG.! y+ hx, hy :: Vertex+ hx = headHld VG.! x+ hy = headHld VG.! y+ ihx, ihy :: VertexHld+ ihx = indexHld VG.! hx+ ihy = indexHld VG.! hy+ phx, phy :: VertexHld+ phx = parentHld VG.! hx+ phy = parentHld VG.! hy++-- | \(O(1)\) Returns a half-open interval of `VertexHld` \([\mathrm{start}, \mathrm{end})\) that+-- corresponds to the subtree segments rooted at the given @subtreeRoot@.+--+-- @since 1.1.0.0+{-# INLINE subtreeSegmentInclusive #-}+subtreeSegmentInclusive :: (HasCallStack) => Hld -> Vertex -> (VertexHld, VertexHld)+subtreeSegmentInclusive Hld {..} subtreeRoot = (ir, ir + sr - 1)+ where+ ir = indexHld VG.! subtreeRoot+ sr = subtreeSizeHld VG.! subtreeRoot++-- | \(O(1)\) Returns `True` if \(u\) is in a subtree of \(r\).+--+-- @since 1.1.0.0+{-# INLINE isInSubtree #-}+isInSubtree :: (HasCallStack) => Hld -> Vertex -> Vertex -> Bool+isInSubtree hld@Hld {..} r_ u = l <= iu && iu <= r+ where+ (!l, !r) = subtreeSegmentInclusive hld r_+ !iu = indexHld VG.! u++-- | Represents whether weights are put on vertices or edges.+--+-- @since 1.1.0.0+data WeightPolicy+ = -- | Weights are put on vertices.+ --+ -- @since 1.1.0.0+ WeightsAreOnVertices+ | -- | Weights are put on edges.+ --+ -- @since 1.1.0.0+ WeightsAreOnEdges+ deriving+ ( -- | @since 1.1.0.0+ Eq,+ -- | @since 1.1.0.0+ Show+ )++-- | \(O(\log n f)\) Returns product of the path between \(u\) and \(v\), using the user functions+-- of time complexity \(O(f)\).+--+-- @since 1.1.0.0+{-# INLINE prod #-}+prod ::+ (HasCallStack, Monoid mono, Monad m) =>+ -- | The `WeightPolicy`.+ WeightPolicy ->+ -- | The `Hld`.+ Hld ->+ -- | User function for getting products in \([u, v)\), where \(u < v\) and+ -- \(\mathrm{depth}(u) < \mathrm{depth}(v)\).+ (VertexHld -> VertexHld -> m mono) ->+ -- | User function for getting products in \([u, v)\), where \(u < v\) and+ -- \(\mathrm{depth}(u) > \mathrm{depth}(v)\).+ (VertexHld -> VertexHld -> m mono) ->+ -- | \(u\).+ Vertex ->+ -- | \(v\).+ Vertex ->+ -- | Product of the path between \(u\) and \(v\).+ m mono+prod weightPolicy hld prodF prodB u0 v0 = do+ foldM+ ( \ !acc (!u, !v) -> do+ !x <-+ if u <= v+ then prodF u $ v + 1+ else prodB v $ u + 1+ pure $! acc <> x+ )+ mempty+ (pathSegmentsInclusive weightPolicy hld u0 v0)
+ src/AtCoder/Extra/Tree/TreeMonoid.hs view
@@ -0,0 +1,297 @@+{-# LANGUAGE RecordWildCards #-}++-- | Integration of segment trees with the heavy-light decomposition technique. Computes monoid+-- products on a path in \(O(\log^2 n)\) time or on a subtree in \(O(\log n)\) time.+--+-- - If vertices have weights, create a `TreeMonoid` with `fromVerts`.+-- - If edges have weights, create a tree monoid with `fromEdges`.+--+-- ==== __(Internals) Weights on edges__+--+-- When vertices are unweighted and only edges have weights, treat edges as new vertices or assign+-- edge weights to the deeper vertex.+--+-- Idea 1. Convert edges into new vertices. This is inefficient.+--+-- @+-- o--o--o --> o-x-o-x-o+-- @+--+-- Idea 2. Assign edge weight to the deeper vertex. The is the internal implementation of+-- `fromEdges` and LCAs are ignored on `prod`:+--+-- @+-- o+-- | <--- edge 1+-- o <- write weight 1 here+-- | <--- edge 2+-- o <- write weight 2 here+-- @+--+-- ==== __Example (1): Weights are on vertices__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import AtCoder.Extra.Tree.Hld qualified as Hld+-- >>> import AtCoder.Extra.Tree.TreeMonoid qualified as TM+-- >>> import Data.Semigroup (Sum (..))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> -- 0--1--2--3+-- >>> -- ++-- >>> -- +--4--5+-- >>> let n = 6+-- >>> let tree = Gr.build' n . Gr.swapDupe' $ VU.fromList [(0, 1), (1, 2), (2, 3), (1, 4), (4, 5)]+-- >>> let weights = VU.generate n Sum -- vertex `i` is given weight of `i`+-- >>> let hld = Hld.new tree+-- >>> tm <- TM.fromVerts hld {- `Sum` is commutative -} Commute weights+-- >>> TM.prod tm 1 3+-- Sum {getSum = 6}+--+-- >>> TM.prodSubtree tm 1+-- Sum {getSum = 15}+--+-- >>> TM.write tm 1 $ Sum 10+-- >>> TM.prod tm 1 3+-- Sum {getSum = 15}+--+-- ==== __Example (2): Weights are on edges__+-- >>> import AtCoder.Extra.Graph qualified as Gr+-- >>> import AtCoder.Extra.Tree.Hld qualified as Hld+-- >>> import AtCoder.Extra.Tree.TreeMonoid qualified as TM+-- >>> import Data.Semigroup (Sum (..))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> -- 0--1--2--3+-- >>> -- ++-- >>> -- +--4--5+-- >>> let n = 6+-- >>> let edges = VU.fromList [(0, 1, Sum (1 :: Int)), (1, 2, Sum 2), (2, 3, Sum 3), (1, 4, Sum 4), (4, 5, Sum 5)]+-- >>> let tree = Gr.build n $ Gr.swapDupe edges+-- >>> let hld = Hld.new tree+-- >>> tm <- TM.fromEdges hld {- `Sum` is commutative -} Commute edges+-- >>> TM.prod tm 1 3+-- Sum {getSum = 5}+--+-- >>> TM.prodSubtree tm 1+-- Sum {getSum = 14}+--+-- >>> TM.write tm 2 $ Sum 10+-- >>> TM.prod tm 1 3+-- Sum {getSum = 13}+--+-- @since 1.1.0.0+module AtCoder.Extra.Tree.TreeMonoid+ ( -- * TreeMonoid+ TreeMonoid,+ Vertex,+ VertexHld,+ Commutativity (..),++ -- * Constructors+ fromVerts,+ fromEdges,++ -- * Segment tree methods++ -- ** Reading+ prod,+ prodSubtree,+ read,++ -- ** Modifications+ write,+ exchange,+ modify,+ modifyM,+ )+where++import AtCoder.Extra.Tree.Hld qualified as Hld+import AtCoder.Internal.Assert qualified as ACIA+import AtCoder.SegTree qualified as ST+import Control.Monad+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Monoid (Dual (..))+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 (read)++-- | Original graph vertex.+--+-- @since 1.1.0.0+type Vertex = Int++-- | Vertex reindexed by `indexHld`.+--+-- @since 1.1.0.0+type VertexHld = Vertex++-- | A wrapper for `Hld` getting product on paths on a tree using `Hld` and segment tree(s).+--+-- @since 1.1.0.0+data TreeMonoid a s = TreeMonoid+ { -- | Borrowed Hld.+ hldTM :: !Hld.Hld,+ -- | Indicates if it's targetting commutative monoids.+ commuteTM :: !Commutativity,+ -- | Indicates if it's targetting edge weights (If not, it's targetting vertex weights).+ weightPolicyTM :: !Hld.WeightPolicy,+ -- | Segment tree for getting products upwards.+ segFTM :: !(ST.SegTree s a),+ -- | Segment tree for getting products downwards. Only created when the monoid is+ -- `NonCommute`.+ segBTM :: !(ST.SegTree s (Dual a))+ }++-- | Represents whether a monoid is commutative or noncommutative.+--+-- @since 1.1.0.0+data Commutativity+ = -- | Commutative: \(a \cdot b = b \cdot a\).+ --+ -- @since 1.1.0.0+ Commute+ | -- | Noncommutative: \(a \cdot b \neq b \cdot a\).+ --+ -- @since 1.1.0.0+ NonCommute+ deriving+ ( -- | @since 1.1.0.0+ Eq,+ -- | @since 1.1.0.0+ Show+ )++-- | \(O(n)\)+buildImpl ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ Hld.Hld ->+ Commutativity ->+ Hld.WeightPolicy ->+ VU.Vector a ->+ m (TreeMonoid a (PrimState m))+buildImpl hldTM commuteTM weightPolicyTM weights = do+ segFTM <- ST.build weights+ segBTM <-+ case commuteTM of+ Commute -> ST.build VU.empty+ NonCommute -> ST.build $ VU.map Dual weights+ pure TreeMonoid {..}++-- | \(O(n)\) Creates a `TreeMonoid` with weights on vertices.+--+-- @since 1.1.0.0+fromVerts ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | `Hld.Hld`.+ Hld.Hld ->+ -- | Whether the monoid is commutative or not.+ Commutativity ->+ -- | The vertex weights.+ VU.Vector a ->+ -- | A `TreeMonoid` with weights on vertices.+ m (TreeMonoid a (PrimState m))+fromVerts hld@Hld.Hld {indexHld} commuteTM xs_ = do+ let !_ = ACIA.runtimeAssert (VU.length indexHld == VU.length xs_) $ "AtCoder.Extra.Tree.TreeMonoid.fromVerts: vertex number mismatch (`" ++ show (VU.length indexHld) ++ "` and `" ++ show (VU.length xs_) ++ "`)"+ let !xs = VU.create $ do+ vec <- VUM.unsafeNew $ VU.length xs_+ VU.iforM_ xs_ $ \i x -> do+ VGM.write vec (indexHld VG.! i) x+ pure vec+ buildImpl hld commuteTM Hld.WeightsAreOnVertices xs++-- | \(O(n)\) Creates a `TreeMonoid` with weignts on edges. The edges are not required to be+-- duplicated: only one of \((u, v, w)\) or \((v, u, w)\) is needed.+--+-- @since 1.1.0.0+fromEdges ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | `Hld.Hld`.+ Hld.Hld ->+ -- | Whether the monoid is commutative or not.+ Commutativity ->+ -- | Input edges.+ VU.Vector (Vertex, Vertex, a) ->+ -- | A `TreeMonoid` with weights on edges.+ m (TreeMonoid a (PrimState m))+fromEdges hld@Hld.Hld {indexHld} commuteTM edges = do+ let !xs = VU.create $ do+ vec <- VUM.unsafeNew $ VU.length indexHld+ VU.forM_ edges $ \(!u, !v, !w) -> do+ let u' = indexHld VG.! u+ let v' = indexHld VG.! v+ VGM.write vec (max u' v') w+ pure vec+ buildImpl hld commuteTM Hld.WeightsAreOnEdges xs++-- | \(O(\log^2 n)\) Returns the product of the path between two vertices \(u\), \(v\) (invlusive).+--+-- @since 1.1.0.0+prod :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> Vertex -> m a+prod TreeMonoid {..} u v = do+ case commuteTM of+ Commute -> Hld.prod weightPolicyTM hldTM (ST.prod segFTM) (ST.prod segFTM) u v+ NonCommute -> Hld.prod weightPolicyTM hldTM (ST.prod segFTM) (\l r -> getDual <$> ST.prod segBTM l r) u v++-- | \(O(\log n)\) Returns the product of the subtree rooted at the given `Vertex`.+--+-- @since 1.1.0.0+prodSubtree :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a+prodSubtree TreeMonoid {..} subtreeRoot = do+ let (!l, !r) = Hld.subtreeSegmentInclusive hldTM subtreeRoot+ case weightPolicyTM of+ Hld.WeightsAreOnVertices -> ST.prod segFTM l (r + 1)+ Hld.WeightsAreOnEdges -> do+ -- ignore the root of the subtree, which has the minimum index among the subtree vertices+ if l == r+ then pure mempty+ else ST.prod segFTM (l + 1) (r + 1)++-- | \(O(1)\) Reads a `TreeMonoid` value on a `Vertex`.+--+-- @since 1.1.0.0+read :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> m a+read TreeMonoid {..} i_ = do+ let !i = Hld.indexHld hldTM VG.! i_+ ST.read segFTM i++-- | \(O(\log n)\) Write a `TreeMonoid` value on a `Vertex`.+--+-- @since 1.1.0.0+write :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m ()+write TreeMonoid {..} i_ x = do+ let !i = Hld.indexHld hldTM VG.! i_+ ST.write segFTM i x+ when (commuteTM == NonCommute) $ do+ ST.write segBTM i $ Dual x++-- | \(O(\log n)\) Exchanges a `TreeMonoid` value on a `Vertex`.+--+-- @since 1.1.0.0+exchange :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> Vertex -> a -> m a+exchange TreeMonoid {..} i_ x = do+ let !i = Hld.indexHld hldTM VG.! i_+ !res <- ST.exchange segFTM i x+ when (commuteTM == NonCommute) $ do+ ST.write segBTM i $ Dual x+ pure res++-- | \(O(\log n)\) Modifies a `TreeMonoid` value on a `Vertex`.+--+-- @since 1.1.0.0+modify :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> (a -> a) -> Int -> m ()+modify TreeMonoid {..} f i_ = do+ let !i = Hld.indexHld hldTM VG.! i_+ ST.modify segFTM f i+ when (commuteTM == NonCommute) $ do+ ST.modify segBTM (Dual . f . getDual) i++-- | \(O(\log n)\) Modifies a `TreeMonoid` value on a `Vertex`.+--+-- @since 1.1.0.0+modifyM :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => TreeMonoid a (PrimState m) -> (a -> m a) -> Int -> m ()+modifyM TreeMonoid {..} f i_ = do+ let !i = Hld.indexHld hldTM VG.! i_+ ST.modifyM segFTM f i+ when (commuteTM == NonCommute) $ do+ ST.modifyM segBTM ((Dual <$>) . f . getDual) i
+ src/AtCoder/Extra/WaveletMatrix.hs view
@@ -0,0 +1,407 @@+{-# LANGUAGE RecordWildCards #-}++-- | A static Wavelet Matrix.+--+-- ==== Notation+-- Let \(S\) be the set of values in your wavelet matrix. We use \(|S|\) to denote the number of+-- distinct values contained within this set \((|S| \lt n)\).+--+-- @since 1.1.0.0+module AtCoder.Extra.WaveletMatrix+ ( -- * Wavelet Matrix+ WaveletMatrix (..),++ -- * Constructors+ build,++ -- * Access (indexing)+ access,++ -- * Rank (count)+ rank,+ rankBetween,++ -- * Selection++ -- | ==== __Example__+ -- >>> import AtCoder.Extra.WaveletMatrix qualified as WM+ -- >>> import Data.Vector.Unboxed qualified as VU+ -- >>> let wm = WM.build $ VU.fromList [1,1,2,1,3]+ -- >>> WM.select wm 1+ -- Just 0+ -- >>> WM.selectKth wm 2 1+ -- Just 3+ -- >>> WM.selectIn wm {- [l, r) -} 1 4 {- x -} 1+ -- Just 1+ -- >>> WM.selectKthIn wm {- [l, r) -} 1 4 {- k -} 1 {- x -} 1+ -- Just 3+ select,+ selectKth,+ selectIn,+ selectKthIn,++ -- * Quantile (value-ordered access)+ kthLargestIn,+ ikthLargestIn,+ kthSmallestIn,+ ikthSmallestIn,+ -- unsafeKthLargestIn,+ -- unsafeIKthLargestIn,+ -- unsafeKthSmallestIn,+ -- unsafeIKthSmallestIn,++ -- * Lookup+ lookupLE,+ lookupLT,+ lookupGE,+ lookupGT,++ -- * Conversions+ assocsIn,+ descAssocsIn,+ )+where++import AtCoder.Extra.Bisect+import AtCoder.Extra.WaveletMatrix.Raw qualified as Rwm+import Control.Monad+import Data.Maybe (fromJust, fromMaybe)+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Generic qualified as VG+import Data.Vector.Unboxed qualified as VU++-- | A static Wavelet Matrix.+--+-- @since 1.1.0.0+data WaveletMatrix = WaveletMatrix+ { -- | The internal wavelet matrix, where index compression is not automatically performed.+ --+ -- @since 1.1.0.0+ rawWM :: !Rwm.RawWaveletMatrix,+ -- | Index compression dictionary.+ --+ -- @since 1.1.0.0+ xDictWM :: !(VU.Vector Int)+ }++-- | \(O(n \log n)\) Creates a `WaveletMatrix` from an array \(a\).+--+-- @since 1.1.0.0+{-# INLINE build #-}+build :: VU.Vector Int -> WaveletMatrix+build ys =+ let !xDictWM = VU.uniq $ VU.modify (VAI.sortBy compare) ys+ !ys' = VU.map (fromJust . lowerBound xDictWM) ys+ !rawWM = Rwm.build (VG.length ys) ys'+ in WaveletMatrix {..}++-- | \(O(\log |S|)\) Returns \(a[k]\) or `Nothing` if the index is out of the bounds. Try to use the+-- original array if you can.+--+-- @since 1.1.0.0+{-# INLINE access #-}+access :: WaveletMatrix -> Int -> Maybe Int+access WaveletMatrix {..} i = (xDictWM VG.!) <$> Rwm.access rawWM i++-- | \(O(\log |S|)\) Returns the number of \(y\) in \([l, r)\).+--+-- @since 1.1.0.0+{-# INLINE rank #-}+rank ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The number of \(y\) in \([l, r)\).+ Int+rank wm l r y = rankBetween wm l r y (y + 1)++-- | \(O(\log |S|)\) Returns the number of \(y\) in \([l, r) \times [y_1, y_2)\).+--+-- @since 1.1.0.0+{-# INLINE rankBetween #-}+rankBetween ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_1\)+ Int ->+ -- | \(y_2\)+ Int ->+ -- | The number of \(y\) in \([l, r) \times [y_1, y_2)\).+ Int+rankBetween WaveletMatrix {..} l r y1 y2+ | not $ 0 <= l && l < r && r <= n = 0+ | y1' >= y2' = 0+ | otherwise = Rwm.rankBetween rawWM l r y1' y2'+ where+ -- Handles the case @yl@ or @yr@ is not in the dict+ n = Rwm.lengthRwm rawWM+ y1' = fromMaybe n (bisectR 0 (VG.length xDictWM) ((< y1) . VG.unsafeIndex xDictWM))+ y2' = maybe (-1) (+ 1) (bisectL 0 (VG.length xDictWM) ((< y2) . VG.unsafeIndex xDictWM))++-- | \(O(\log |S|)\) Returns the index of the first \(y\) in \(a\), or `Nothing` if \(y\) is+-- not found.+--+-- @since 1.1.0.0+{-# INLINE select #-}+select :: WaveletMatrix -> Int -> Maybe Int+select wm = selectKth wm 0++-- | \(O(\log |S|)\) Returns the index of the \(k\)-th occurrence (0-based) of \(y\), or `Nothing`+-- if no such occurrence exists.+--+-- @since 1.1.0.0+{-# INLINE selectKth #-}+selectKth ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(k\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The index of \(k\)-th \(y\)+ Maybe Int+selectKth WaveletMatrix {..} k y = do+ i <- lowerBound xDictWM y+ -- TODO: we don't need such an explicit branch?+ let !y' = xDictWM VG.! i+ guard $ y' == y+ Rwm.selectKth rawWM k i++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns the index of the first occurrence+-- (0-based) of \(y\) in the sequence, or `Nothing` if no such occurrence exists.+--+-- @since 1.1.0.0+{-# INLINE selectIn #-}+selectIn ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The index of the first \(y\) in \([l, r)\).+ Maybe Int+selectIn wm l r = selectKthIn wm l r 0++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns the index of the \(k\)-th occurrence+-- (0-based) of \(y\) in the sequence, or `Nothing` if no such occurrence exists.+--+-- @since 1.1.0.0+{-# INLINE selectKthIn #-}+selectKthIn ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The index of the \(k\)-th \(y\) in \([l, r)\).+ Maybe Int+selectKthIn WaveletMatrix {..} l r k y = do+ i <- lowerBound xDictWM y+ -- TODO: we don't need such an explicit branch?+ let !y' = xDictWM VG.! i+ guard $ y' == y+ Rwm.selectKthIn rawWM l r k i++-- | \(O(\log |S|)\) Given the interval \([l, r)\), returns the index of the \(k\)-th (0-based)+-- largest value. Note that duplicated values are treated as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE kthLargestIn #-}+kthLargestIn ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \(k\)-th largest \(y\) in \([l, r)\)+ Maybe Int+kthLargestIn WaveletMatrix {..} l r k+ | Just !y <- Rwm.kthLargestIn rawWM l r k = Just $ xDictWM VG.! y+ | otherwise = Nothing++-- | \(O(\log |S|)\) Given the interval \([l, r)\), returns both the index and the value of the+-- \(k\)-th (0-based) largest value. Note that duplicated values are treated as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE ikthLargestIn #-}+ikthLargestIn ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \((i, y)\) for \(k\)-th largest \(y\) in \([l, r)\)+ Maybe (Int, Int)+ikthLargestIn WaveletMatrix {..} l r k+ | Just (!i, !y) <- Rwm.ikthLargestIn rawWM l r k = Just (i, xDictWM VG.! y)+ | otherwise = Nothing++-- | \(O(\log |S|)\) Given the interval \([l, r)\), returns the index of the \(k\)-th (0-based)+-- smallest value. Note that duplicated values are treated as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE kthSmallestIn #-}+kthSmallestIn ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \(k\)-th largest \(y\) in \([l, r)\)+ Maybe Int+kthSmallestIn WaveletMatrix {..} l r k+ | Just !y <- Rwm.kthSmallestIn rawWM l r k = Just $ xDictWM VG.! y+ | otherwise = Nothing++-- | \(O(\log |S|)\) Given the interval \([l, r)\), returns both the index and the value of the+-- \(k\)-th (0-based) smallest value. Note that duplicated values are treated as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE ikthSmallestIn #-}+ikthSmallestIn ::+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \((i, y)\) for \(k\)-th largest \(y\) in \([l, r)\)+ Maybe (Int, Int)+ikthSmallestIn WaveletMatrix {..} l r k+ | Just (!i, !y) <- Rwm.ikthSmallestIn rawWM l r k = Just (i, xDictWM VG.! y)+ | otherwise = Nothing++-- | \(O(\log |S|)\)+--+-- @since 1.1.0.0+{-# INLINE unsafeKthSmallestIn #-}+unsafeKthSmallestIn :: WaveletMatrix -> Int -> Int -> Int -> Int+unsafeKthSmallestIn WaveletMatrix {..} l r k =+ xDictWM VG.! Rwm.unsafeKthSmallestIn rawWM l r k++-- | \(O(\log |S|)\) Looks up the maximum \(y\) in \([l, r) \times (-\infty, y_0]\).+--+-- @since 1.1.0.0+{-# INLINE lookupLE #-}+lookupLE ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Maximum \(y\) in \([l, r) \times (-\infty, y_0]\)+ Maybe Int+lookupLE wm l r y0+ | r' == l' = Nothing+ | rank_ == 0 = Nothing+ | otherwise = Just $ unsafeKthSmallestIn wm l' r' (rank_ - 1)+ where+ -- clamp+ l' = max 0 l+ r' = min (Rwm.lengthRwm (rawWM wm)) r+ rank_ = rankBetween wm l' r' minBound (y0 + 1)++-- | \(O(\log |S|)\) Looks up the maximum \(y\) in \([l, r) \times (-\infty, y_0)\).+--+-- @since 1.1.0.0+{-# INLINE lookupLT #-}+lookupLT ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Maximum \(y\) in \([l, r) \times (-\infty, y_0)\)+ Maybe Int+lookupLT wm l r y0 = lookupLE wm l r (y0 - 1)++-- | \(O(\log |S|)\) Looks up the minimum \(y\) in \([l, r) \times [y_0, \infty)\).+--+-- @since 1.1.0.0+{-# INLINE lookupGE #-}+lookupGE ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Minimum \(y\) in \([l, r) \times [y_0, \infty)\).+ Maybe Int+lookupGE wm l r y0+ | r' == l' = Nothing+ | rank_ >= r - l = Nothing+ | otherwise = Just $ unsafeKthSmallestIn wm l r rank_+ where+ -- clamp+ l' = max 0 l+ r' = min (Rwm.lengthRwm (rawWM wm)) r+ rank_ = rankBetween wm l' r' minBound y0++-- | \(O(\log |S|)\) Looks up the minimum \(y\) in \([l, r) \times (y_0, \infty)\).+--+-- @since 1.1.0.0+{-# INLINE lookupGT #-}+lookupGT ::+ -- | A wavelet matrix+ WaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Minimum \(y\) in \([l, r) \times (y_0, \infty)\)+ Maybe Int+lookupGT wm l r y0 = lookupGE wm l r (y0 + 1)++-- | \(O(\min(|S|, L) \log |S|)\) Collects \((y, \mathrm{rank}(y))\) in range \([l, r)\) in+-- ascending order of \(y\). Note that it's only fast when the \(|S|\) is very small.+--+-- @since 1.1.0.0+{-# INLINE assocsIn #-}+assocsIn :: WaveletMatrix -> Int -> Int -> [(Int, Int)]+assocsIn WaveletMatrix {..} l r = Rwm.assocsWith rawWM l r (xDictWM VG.!)++-- | \(O(\min(|S|, L) \log |S|)\) Collects \((y, \mathrm{rank}(y))\) in range \([l, r)\) in+-- descending order of \(y\). Note that it's only fast when the \(|S|\) is very small.+--+-- @since 1.1.0.0+{-# INLINE descAssocsIn #-}+descAssocsIn :: WaveletMatrix -> Int -> Int -> [(Int, Int)]+descAssocsIn WaveletMatrix {..} l r = Rwm.descAssocsInWith rawWM l r (xDictWM VG.!)
+ src/AtCoder/Extra/WaveletMatrix/BitVector.hs view
@@ -0,0 +1,179 @@+{-# LANGUAGE RecordWildCards #-}++-- | A compact bit vector, a collection of bits that can process @rank@ in \(O(1)\) and @select@ in+-- \(O(\log n)\).+--+-- @since 1.1.0.0+module AtCoder.Extra.WaveletMatrix.BitVector+ ( -- * Bit vector+ BitVector (..),++ -- * Constructor+ build,++ -- * (Internal) Word-based cumultaive sum+ wordSize,+ csumInPlace,++ -- * Rank+ rank0,+ rank1,++ -- * Select+ select0,+ select1,+ selectKthIn0,+ selectKthIn1,+ )+where++import AtCoder.Extra.Bisect (bisectL)+import Control.Monad.Primitive (PrimMonad (PrimState))+import Data.Bit (Bit (..))+import Data.Bits (popCount)+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++-- | A compact bit vector.+--+-- @since 1.1.0.0+data BitVector = BitVector+ { -- | Packed bits.+ --+ -- @since 1.1.0.0+ bitsBv :: !(VU.Vector Bit),+ -- | Cumulative sum of bits by 64 words.+ --+ -- @since 1.1.0.0+ csumBv :: !(VU.Vector Int)+ -- we could use Word32 for csumBv, as 2^32 is large enough+ }+ deriving (Eq, Show)++-- | \(O(n)\) Creates a `BitVector`.+--+-- @since 1.1.0.0+{-# INLINE build #-}+build :: VU.Vector Bit -> BitVector+build bitsBv =+ let csumBv = VU.create $ do+ vec <- VUM.replicate ((VU.length bitsBv + 63) `div` 64 + 1) 0+ _ <- csumInPlace vec bitsBv+ pure vec+ in BitVector {..}++-- | The block size \(64\) for the internal cumultaive sum in the bit vector.+--+-- @since 1.1.0.0+{-# INLINE wordSize #-}+wordSize :: Int+wordSize = 64++-- | \(O(n)\) Calculates the cumulative sum in-place for the bit vector and returns the sum.+--+-- @since 1.1.0.0+{-# INLINE csumInPlace #-}+csumInPlace ::+ (PrimMonad m) =>+ -- | Cumulative sum of length \(\lceil |\mathrm{bits}| / 64 \rceil\).+ VUM.MVector (PrimState m) Int ->+ -- | Bits+ VU.Vector Bit ->+ -- | Sum of the bits+ m Int+csumInPlace csum bits = do+ VGM.unsafeWrite csum 0 (0 :: Int)++ -- Calcuate popCount by word. TODO: use `castToWords` for most elements+ VU.ifoldM'+ ( \ !acc i wordSum -> do+ let !acc' = acc + wordSum+ VGM.unsafeWrite csum (i + 1) acc'+ pure acc'+ )+ (0 :: Int)+ $ VU.unfoldrExactN+ (VGM.length csum - 1)+ (\bits' -> (popCount (VU.take wordSize bits'), VU.drop wordSize bits'))+ bits++-- | \(O(1)\) Counts the number of \(0\) bits in the interval \([0, i)\).+--+-- @since 1.1.0.0+{-# INLINE rank0 #-}+rank0 :: BitVector -> Int -> Int+rank0 bv i = i - rank1 bv i++-- | \(O(1)\) Counts the number of \(1\) bits in an interval \([0, i)\).+--+-- @since 1.1.0.0+{-# INLINE rank1 #-}+rank1 :: BitVector -> Int -> Int+rank1 BitVector {..} i = fromCSum + fromRest+ where+ -- TODO: check bounds for i?+ (!nWords, !nRest) = i `divMod` wordSize+ fromCSum = VG.unsafeIndex csumBv nWords+ fromRest = popCount . VU.take nRest . VU.drop (nWords * wordSize) $ bitsBv++-- | \(O(\log n)\) Returns the index of \(k\)-th \(0\) (0-based), or `Nothing` if no such bit exists.+--+-- @since 1.1.0.0+{-# INLINE select0 #-}+select0 :: BitVector -> Int -> Maybe Int+select0 bv = selectKthIn0 bv 0 (VG.length (bitsBv bv))++-- | \(O(\log n)\) Returns the index of \(k\)-th \(1\) (0-based), or `Nothing` if no such bit exists.+--+-- @since 1.1.0.0+{-# INLINE select1 #-}+select1 :: BitVector -> Int -> Maybe Int+select1 bv = selectKthIn1 bv 0 (VG.length (bitsBv bv))++-- | \(O(\log n)\) Returns the index of \(k\)-th \(0\) (0-based) in \([l, r)\), or `Nothing` if no+-- such bit exists.+--+-- @since 1.1.0.0+{-# INLINE selectKthIn0 #-}+selectKthIn0 ::+ -- | A bit vector+ BitVector ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | The index of \(k\)-th \(0\) in \([l, r)\)+ Maybe Int+selectKthIn0 bv l r k+ | k < 0 || nZeros <= k = Nothing+ | otherwise = bisectL l r $ \i -> rank0 bv i - rankL0 < k + 1+ where+ nZeros = rank0 bv r - rankL0+ rankL0 = rank0 bv l++-- | \(O(\log n)\) Returns the index of \(k\)-th \(1\) (0-based) in \([l, r)\), or `Nothing` if no+-- such bit exists.+--+-- @since 1.1.0.0+{-# INLINE selectKthIn1 #-}+selectKthIn1 ::+ -- | A bit vector+ BitVector ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | The index of \(k\)-th \(1\) in \([l, r)\)+ Maybe Int+selectKthIn1 bv l r k+ | k < 0 || nOnes <= k = Nothing+ | otherwise = bisectL l r $ \i -> rank1 bv i - rankL1 < k + 1+ where+ nOnes = rank1 bv r - rankL1+ rankL1 = rank1 bv l
+ src/AtCoder/Extra/WaveletMatrix/Raw.hs view
@@ -0,0 +1,651 @@+{-# LANGUAGE RecordWildCards #-}++-- original implementation:+-- <https://miti-7.hatenablog.com/entry/2018/04/28/152259>++-- NOTE: We could integrate cumulative sum / fenwick tree / segment tree.+-- NOTE: `topK` and `intersects` are not implemented as they are slow.++-- | A static Wavelet Matrix without automatic index comperssion. Consider using+-- @AtCoder.Extra.WaveletMatrix@ instead.+--+-- @since 1.1.0.0+module AtCoder.Extra.WaveletMatrix.Raw+ ( -- * RawWaveletMatrix+ RawWaveletMatrix (..),++ -- * Constructors+ build,++ -- * Access (indexing)+ access,++ -- * rank+ rankLT,+ rank,+ rankBetween,++ -- * Select+ select,+ selectKth,+ selectIn,+ selectKthIn,++ -- * Quantile (value-ordered access)++ -- ** Safe (total)+ kthSmallestIn,+ ikthSmallestIn,+ kthLargestIn,+ ikthLargestIn,++ -- ** Unsafe+ unsafeKthSmallestIn,+ unsafeIKthSmallestIn,+ unsafeKthLargestIn,+ unsafeIKthLargestIn,++ -- * Lookup+ lookupLE,+ lookupLT,+ lookupGE,+ lookupGT,++ -- * Conversions+ assocsIn,+ assocsWith,+ descAssocsIn,+ descAssocsInWith,+ )+where++import AtCoder.Extra.WaveletMatrix.BitVector qualified as BV+import AtCoder.Internal.Assert qualified as ACIA+import AtCoder.Internal.Bit qualified as ACIB+import Control.Monad.ST (runST)+import Data.Bit (Bit (..))+import Data.Bits (bit, countTrailingZeros, setBit, testBit, (.|.))+import Data.Maybe+import Data.Vector qualified as V+import Data.Vector.Algorithms.Radix qualified as VAR+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)++-- | A static Wavelet Matrix without automatic index comperssion.+--+-- @since 1.1.0.0+data RawWaveletMatrix = RawWaveletMatrix+ { -- | \(\lceil \log_2 N \rceil\).+ --+ -- @since 1.1.0.0+ heightRwm :: {-# UNPACK #-} !Int,+ -- | The length of the original array.+ --+ -- @since 1.1.0.0+ lengthRwm :: {-# UNPACK #-} !Int,+ -- | The bit matrix. Each row represents (heightRwm - 1 - iRow) bit's on/off.+ --+ -- @since 1.1.0.0+ bitsRwm :: !(V.Vector BV.BitVector),+ -- | The number of zeros bits in each row in the bit matrix.+ --+ -- @since 1.1.0.0+ nZerosRwm :: !(VU.Vector Int)+ }+ deriving (Eq, Show)++-- | \(O(n \log n)\) Creates a `RawWaveletMatrix` from a vector \(a\).+--+-- @since 1.1.0.0+{-# INLINE build #-}+build ::+ (HasCallStack) =>+ -- | The number of different values in the compressed vector.+ Int ->+ -- | A compressed vector+ VU.Vector Int ->+ -- | A wavelet matrix+ RawWaveletMatrix+build nx xs+ | nx < 0 = error "AtCoder.Extra.WaveletMatrix.Raw.build: given negative `n`"+ | otherwise = runST $ do+ -- TODO: less mutable variables+ orgBits <- VUM.replicate (lengthRwm * heightRwm) $ Bit False+ orgCsum <- VUM.replicate (lenCSum * heightRwm) (0 :: Int)+ nZeros <- VUM.unsafeNew heightRwm++ -- views by row over the contiguous memory:+ let !bits = V.unfoldrExactN heightRwm (VUM.splitAt lengthRwm) orgBits+ let !csums = V.unfoldrExactN heightRwm (VUM.splitAt lenCSum) orgCsum++ -- the vector will be sorted by bits.+ vec <- VU.thaw xs+ V.izipWithM_+ ( \iRow bitVec csum -> do+ let !iBit = heightRwm - 1 - iRow+ vec' <- VU.unsafeFreeze vec+ VU.iforM_ vec' $ \i x -> do+ VGM.unsafeWrite bitVec i . Bit $ testBit x iBit++ -- csum.+ VGM.unsafeWrite csum 0 (0 :: Int)+ bitVec' <- VU.unsafeFreeze bitVec++ -- get popCount by word. TODO: use `castToWords` for most elements+ nOnes <- BV.csumInPlace csum bitVec'+ VGM.unsafeWrite nZeros iRow (lengthRwm - nOnes)++ -- preform a stable sort by the bit:+ VAR.sortBy 2 2 (\_ x -> fromEnum (testBit x iBit)) vec+ )+ bits+ csums+ nZerosRwm <- VU.unsafeFreeze nZeros+ bits' <- V.unfoldrExactN heightRwm (VU.splitAt lengthRwm) <$> VU.unsafeFreeze orgBits+ csums' <- V.unfoldrExactN heightRwm (VU.splitAt lenCSum) <$> VU.unsafeFreeze orgCsum+ let !bitsRwm = V.zipWith BV.BitVector bits' csums'+ pure $ RawWaveletMatrix {..}+ where+ !lengthRwm = VG.length xs+ !lenCSum = (lengthRwm + BV.wordSize - 1) `div` BV.wordSize + 1 -- +1 for the zero+ !heightRwm = countTrailingZeros $ ACIB.bitCeil nx++-- | \(O(\log |S|)\) Returns \(a[k]\) or `Nothing` if the index is out of the bounds. Try to use the+-- original array if you can.+--+-- @since 1.1.0.0+{-# INLINE access #-}+access :: RawWaveletMatrix -> Int -> Maybe Int+access RawWaveletMatrix {..} i0+ | ACIA.testIndex i0 lengthRwm =+ let (!_, !res) =+ V.ifoldl'+ ( \(!i, !acc) !iRow !bits ->+ let Bit !goRight = VG.unsafeIndex (BV.bitsBv bits) i+ !i'+ | goRight = BV.rank1 bits i + VG.unsafeIndex nZerosRwm iRow+ | otherwise = BV.rank0 bits i+ !acc'+ | goRight = setBit acc (heightRwm - 1 - iRow)+ | otherwise = acc+ in (i', acc')+ )+ (i0, 0)+ bitsRwm+ in Just res+ | otherwise = Nothing++-- | \(O(\log |A|)\) Goes down the wavelet matrix for collecting the kth smallest value.+--+-- @since 1.1.0.0+{-# INLINE goDown #-}+goDown :: RawWaveletMatrix -> Int -> Int -> Int -> (Int, Int, Int, Int)+goDown RawWaveletMatrix {..} l_ r_ k_ = V.ifoldl' step (0 :: Int, l_, r_, k_) bitsRwm+ where+ -- It's binary search over the value range. In each row, we'll focus on either 0 bit values or+ -- 1 bit values in [l, r) and update the range to [l', r').+ step (!acc, !l, !r, !k) !iRow !bits+ -- `r0 - l0`, the number of zeros in [l, r), is bigger than or equal to k:+ -- Go left.+ | k < r0 - l0 = (acc, l0, r0, k)+ -- Go right.+ | otherwise =+ let !acc' = acc .|. bit (heightRwm - 1 - iRow)+ !nZeros = VG.unsafeIndex nZerosRwm iRow+ -- every zero bits come to the left after the move.+ !l' = l + nZeros - l0 -- add the number of zeros in [0, l)+ !r' = r + nZeros - r0 -- add the number of zeros in [0, r)+ !k' = k - (r0 - l0) -- `r0 - l0` zeros go left+ in (acc', l', r', k')+ where+ !l0 = BV.rank0 bits l+ !r0 = BV.rank0 bits r++-- | \(O(\log |A|)\) Goes up the wavelet matrix for collecting the value \(x\).+--+-- @since 1.1.0.0+{-# INLINE goUp #-}+goUp :: RawWaveletMatrix -> Int -> Int -> Maybe Int+goUp RawWaveletMatrix {..} i0 x =+ V.ifoldM'+ ( \ !i !iBit !bits ->+ if testBit x iBit+ then BV.select1 bits $ i - nZerosRwm VG.! (heightRwm - 1 - iBit)+ else BV.select0 bits i+ )+ i0+ (V.reverse bitsRwm)++-- | \(O(\log |S|)\) Returns the number of \(y\) in \([l, r) \times [0, y_0)\).+--+-- @since 1.1.0.0+{-# INLINE rankLT #-}+rankLT :: RawWaveletMatrix -> Int -> Int -> Int -> Int+rankLT RawWaveletMatrix {..} l_ r_ xr+ -- REMARK: This is required. The function below cannot handle the case N = 2^i and xr = N.+ | xr >= bit heightRwm = r'_ - l'_+ | xr <= 0 = 0+ | r'_ <= l'_ = 0+ | otherwise =+ let (!res, !_, !_) = V.ifoldl' step (0, l'_, r'_) bitsRwm+ in res+ where+ -- clamp+ l'_ = max 0 l_+ r'_ = min lengthRwm r_+ -- [l, r)+ step (!acc, !l, !r) !iRow !bits =+ let !b = testBit xr (heightRwm - 1 - iRow)+ !l0 = BV.rank0 bits l+ !r0 = BV.rank0 bits r+ in if b+ then (acc + r0 - l0, l - l0 + VG.unsafeIndex nZerosRwm iRow, r - r0 + VG.unsafeIndex nZerosRwm iRow)+ else (acc, l0, r0)++-- | \(O(\log |S|)\) Returns the number of \(y\) in \([l, r)\).+--+-- @since 1.1.0.0+{-# INLINE rank #-}+rank ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The number of \(y\) in \([l, r)\).+ Int+rank wm l r x = rankBetween wm l r x (x + 1)++-- | \(O(\log |S|)\) Returns the number of \(y\) in \([l, r) \times [y_1, y_2)\).+--+-- @since 1.1.0.0+{-# INLINE rankBetween #-}+rankBetween ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_1\)+ Int ->+ -- | \(y_2\)+ Int ->+ -- | The number of \(y\) in \([l, r) \times [y_1, y_2)\).+ Int+rankBetween wm l r lx rx = rankLT wm l r rx - rankLT wm l r lx++-- | \(O(\log |S|)\) Returns the index of the first \(y\) in the sequence, or `Nothing` if \(y\) is+-- not found.+--+-- @since 1.1.0.0+{-# INLINE select #-}+select :: RawWaveletMatrix -> Int -> Maybe Int+select wm = selectKth wm 0++-- | \(O(\log |S|)\) Returns the index of the \(k\)-th occurrence (0-based) of \(y\), or `Nothing`+-- if no such occurrence exists.+--+-- @since 1.1.0.0+{-# INLINE selectKth #-}+selectKth ::+ RawWaveletMatrix ->+ -- | \(k\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The index of \(k\)-th \(y\)+ Maybe Int+selectKth wm = selectKthIn wm 0 (lengthRwm wm)++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns the index of the first occurrence+-- (0-based) of \(y\) in the sequence, or `Nothing` if no such occurrence exists.+--+-- @since 1.1.0.0+{-# INLINE selectIn #-}+selectIn ::+ -- | A wavelet matrix+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | The index of the first \(y\) in \([l, r)\).+ Maybe Int+selectIn wm = selectKthIn wm 0++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns the index of the \(k\)-th occurrence+-- (0-based) of \(y\) in the sequence, or `Nothing` if no such occurrence exists.+--+-- @since 1.1.0.0+{-# INLINE selectKthIn #-}+selectKthIn ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \(y\)+ Int ->+ -- | The index of the \(k\)-th \(y\) in \([l, r)\).+ Maybe Int+selectKthIn wm@RawWaveletMatrix {..} l_ r_ k x+ | not (0 <= x && x < lengthRwm && 0 <= k && k < lengthRwm) = Nothing+ | l'_ < r'_ = inner+ | otherwise = Nothing+ where+ -- clamp+ l'_ = max 0 l_+ r'_ = min lengthRwm r_+ inner :: Maybe Int+ inner+ | rEnd <= lEnd + k = Nothing+ -- go up+ | otherwise = goUp wm (lEnd + k) x+ where+ -- TODO: replace with goDown+ -- Go down. Gets the [l, r) range of @x@ in the last array.+ (!lEnd, !rEnd) =+ V.ifoldl'+ ( \(!l, !r) !iRow !bits ->+ let !l0 = BV.rank0 bits l+ !r0 = BV.rank0 bits r+ in if testBit x (heightRwm - 1 - iRow)+ then (l + nZerosRwm VG.! iRow - l0, r + nZerosRwm VG.! iRow - r0)+ else (l0, r0)+ )+ (l'_, r'_)+ bitsRwm++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns the index of the \(k\)-th (0-based)+-- largest value. Note that duplicated values are counted as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE kthLargestIn #-}+kthLargestIn ::+ -- | A wavelet matrix+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \(k\)-th largest \(y\) in \([l, r)\)+ Maybe Int+kthLargestIn wm l r k+ | k < 0 || k >= r - l = Nothing+ | 0 <= l && l < r && r <= lengthRwm wm = Just $ unsafeKthLargestIn wm l r k+ | otherwise = Nothing++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns both the index and the value of the+-- \(k\)-th (0-based) largest value. Note that duplicated values are counted as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE ikthLargestIn #-}+ikthLargestIn ::+ -- | A wavelet matrix+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \((i, y)\) for \(k\)-th largest \(y\) in \([l, r)\)+ Maybe (Int, Int)+ikthLargestIn wm l r k+ | k < 0 || k >= r - l = Nothing+ | 0 <= l && l < r && r <= lengthRwm wm = Just $ unsafeIKthLargestIn wm l r k+ | otherwise = Nothing++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns the index of the \(k\)-th (0-based)+-- smallest value. Note that duplicated values are counted as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE kthSmallestIn #-}+kthSmallestIn ::+ -- | A wavelet matrix+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \(k\)-th largest \(y\) in \([l, r)\)+ Maybe Int+kthSmallestIn wm l r k+ | k < 0 || k >= r - l = Nothing+ | 0 <= l && l < r && r <= lengthRwm wm = Just $ unsafeKthSmallestIn wm l r k+ | otherwise = Nothing++-- | \(O(\log |S|)\) Given an interval \([l, r)\), it returns both the index and the value of the+-- \(k\)-th (0-based) smallest value. Note that duplicated values are counted as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE ikthSmallestIn #-}+ikthSmallestIn ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(k\)+ Int ->+ -- | \((i, y)\) for \(k\)-th largest \(y\) in \([l, r)\)+ Maybe (Int, Int)+ikthSmallestIn wm l r k+ | k < 0 || k >= r - l = Nothing+ | 0 <= l && l < r && r <= lengthRwm wm = Just $ unsafeIKthSmallestIn wm l r k+ | otherwise = Nothing++-- | \(O(\log a)\) Returns \(k\)-th (0-based) biggest number in \([l, r)\). Note that duplicated+-- values are counted as distinct occurrences.+--+-- @since 1.1.0.0+{-# INLINE unsafeKthLargestIn #-}+unsafeKthLargestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Int+unsafeKthLargestIn wm l r k = unsafeKthSmallestIn wm l r (r - l - (k + 1))++-- | \(O(\log a)\)+--+-- @since 1.1.0.0+{-# INLINE unsafeIKthLargestIn #-}+unsafeIKthLargestIn :: RawWaveletMatrix -> Int -> Int -> Int -> (Int, Int)+unsafeIKthLargestIn wm l r k = unsafeIKthSmallestIn wm l r (r - l - (k + 1))++-- | \(O(\log a)\)+--+-- @since 1.1.0.0+{-# INLINE unsafeKthSmallestIn #-}+unsafeKthSmallestIn :: RawWaveletMatrix -> Int -> Int -> Int -> Int+unsafeKthSmallestIn wm l_ r_ k_ =+ let (!x, !_, !_, !_) = goDown wm l_ r_ k_+ in x++-- | \(O(\log a)\)+--+-- @since 1.1.0.0+{-# INLINE unsafeIKthSmallestIn #-}+unsafeIKthSmallestIn :: RawWaveletMatrix -> Int -> Int -> Int -> (Int, Int)+unsafeIKthSmallestIn wm l_ r_ k_ =+ let (!x, !l, !_, !k) = goDown wm l_ r_ k_+ !i' = fromJust $ goUp wm (l + k) x+ in (i', x)++-- | \(O(\log |S|)\) Looks up the maximum \(y\) in \([l, r) \times (-\infty, y_0]\).+--+-- @since 1.1.0.0+{-# INLINE lookupLE #-}+lookupLE ::+ -- | A wavelet matrix+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Maximum \(y\) in \([l, r) \times (-\infty, y_0]\)+ Maybe Int+lookupLE wm l r x+ | r' == l' = Nothing+ | rank_ == 0 = Nothing+ | otherwise = Just $ unsafeKthSmallestIn wm l' r' (rank_ - 1)+ where+ -- clamp+ l' = max 0 l+ r' = min (lengthRwm wm) r+ rank_ = rankBetween wm l r minBound (x + 1)++-- | \(O(\log a)\) Finds the maximum \(x\) in \([l, r)\) s.t. \(x_{0} \lt x\).+--+-- @since 1.1.0.0+{-# INLINE lookupLT #-}+lookupLT ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(x\)+ Int ->+ -- | Maximum \(y\) in \([l, r) \times (-\infty, y_0)\)+ Maybe Int+lookupLT wm l r x = lookupLE wm l r (x - 1)++-- | \(O(\log |S|)\) Looks up the minimum \(y\) in \([l, r) \times [y_0, \infty)\).+--+-- @since 1.1.0.0+{-# INLINE lookupGE #-}+lookupGE ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Minimum \(y\) in \([l, r) \times [y_0, \infty)\).+ Maybe Int+lookupGE wm l r x+ | r' == l' = Nothing+ | rank_ >= r' - l' = Nothing+ | otherwise =+ Just $ unsafeKthSmallestIn wm l' r' rank_+ where+ -- clamp+ l' = max 0 l+ r' = min (lengthRwm wm) r+ rank_ = rankBetween wm l' r' minBound x++-- | \(O(\log |S|)\) Looks up the minimum \(y\) in \([l, r) \times (y_0, \infty)\).+--+-- @since 1.1.0.0+{-# INLINE lookupGT #-}+lookupGT ::+ RawWaveletMatrix ->+ -- | \(l\)+ Int ->+ -- | \(r\)+ Int ->+ -- | \(y_0\)+ Int ->+ -- | Minimum \(y\) in \([l, r) \times (y_0, \infty)\)+ Maybe Int+lookupGT wm l r x = lookupGE wm l r (x + 1)++-- | \(O(\min(|S|, L) \log |S|)\) Collects \((y, \mathrm{rank}(y))\) in range \([l, r)\) in+-- ascending order of \(y\). Note that it's only fast when the \(|S|\) is very small.+--+-- @since 1.1.0.0+{-# INLINE assocsIn #-}+assocsIn :: RawWaveletMatrix -> Int -> Int -> [(Int, Int)]+assocsIn wm l r = assocsWith wm l r id++-- | \(O(\log A \min(|A|, L))\) Internal implementation of `assocs`.+--+-- @since 1.1.0.0+{-# INLINE assocsWith #-}+assocsWith :: RawWaveletMatrix -> Int -> Int -> (Int -> Int) -> [(Int, Int)]+assocsWith RawWaveletMatrix {..} l_ r_ f+ | l'_ < r'_ = inner (0 :: Int) (0 :: Int) l'_ r'_ []+ | otherwise = []+ where+ -- clamp+ l'_ = max 0 l_+ r'_ = min lengthRwm r_+ -- DFS. [l, r)+ inner !acc iRow !l !r res+ | iRow >= heightRwm =+ let !n = r - l+ !acc' = f acc+ in (acc', n) : res+ | otherwise = do+ let !bits = bitsRwm VG.! iRow+ !l0 = BV.rank0 bits l+ !r0 = BV.rank0 bits r+ !nZeros = nZerosRwm VG.! iRow+ -- go right (visit bigger values first)+ !l' = l + nZeros - l0+ !r' = r + nZeros - r0+ !res'+ | l' < r' = inner (acc .|. bit (heightRwm - 1 - iRow)) (iRow + 1) l' r' res+ | otherwise = res+ !res''+ -- go left+ | l0 < r0 = inner acc (iRow + 1) l0 r0 res'+ | otherwise = res'+ in res''++-- | \(O(\min(|S|, L) \log |S|)\) Collects \((y, \mathrm{rank}(y))\) in range \([l, r)\) in+-- descending order of \(y\). Note that it's only fast when the \(|S|\) is very small.+--+-- @since 1.1.0.0+{-# INLINE descAssocsIn #-}+descAssocsIn :: RawWaveletMatrix -> Int -> Int -> [(Int, Int)]+descAssocsIn wm l r = descAssocsInWith wm l r id++-- | \(O(\log A \min(|A|, L))\) Internal implementation of `descAssoc`.+--+-- @since 1.1.0.0+{-# INLINE descAssocsInWith #-}+descAssocsInWith :: RawWaveletMatrix -> Int -> Int -> (Int -> Int) -> [(Int, Int)]+descAssocsInWith RawWaveletMatrix {..} l_ r_ f+ | l'_ < r'_ = inner (0 :: Int) (0 :: Int) l'_ r'_ []+ | otherwise = []+ where+ -- clamp+ l'_ = max 0 l_+ r'_ = min lengthRwm r_+ -- DFS. [l, r)+ inner !acc iRow !l !r res+ | iRow >= heightRwm =+ let !n = r - l+ !acc' = f acc+ in (acc', n) : res+ | otherwise = do+ let !bits = bitsRwm VG.! iRow+ !l0 = BV.rank0 bits l+ !r0 = BV.rank0 bits r+ !nZeros = nZerosRwm VG.! iRow+ !res'+ -- go left+ | l0 < r0 = inner acc (iRow + 1) l0 r0 res+ | otherwise = res+ -- go right (visit bigger values first)+ !l' = l + nZeros - l0+ !r' = r + nZeros - r0+ !res''+ | l' < r' = inner (acc .|. bit (heightRwm - 1 - iRow)) (iRow + 1) l' r' res'+ | otherwise = res'+ in res''
+ src/AtCoder/Extra/WaveletMatrix2d.hs view
@@ -0,0 +1,277 @@+{-# LANGUAGE RecordWildCards #-}++-- | A 2D, static wavelet matrix with segment tree, that can handle point add and rectangle sum+-- queries. Points cannot be added after construction, but monoid values in each point can be+-- modified later.+--+-- ==== __Example__+-- Create a `WaveletMatrix2d` with initial vertex values:+--+-- >>> import AtCoder.Extra.WaveletMatrix2d qualified as WM+-- >>> import Data.Semigroup (Sum (..))+-- >>> import Data.Vector.Unboxed qualified as VU+-- >>> -- 8 9 10 11+-- >>> -- 4 5 6 7+-- >>> -- 0 1 2 3+-- >>> wm <- WM.build negate $ VU.generate 12 $ \i -> let (!y, !x) = i `divMod` 4 in (x, y, Sum i)+--+-- Read the value at \(x = 2, y = 1\):+--+-- >>> WM.read wm (2, 1)+-- Sum {getSum = 6}+--+-- Other segment tree methods are also available, but in 2D:+--+-- >>> WM.allProd wm -- (0 + 11) * 12 / 2 = 66+-- Sum {getSum = 66}+--+-- >>> WM.prod wm {- x -} 1 3 {- y -} 0 3 -- 1 + 2 + 5 + 6 + 9 + 10+-- Sum {getSum = 33}+--+-- >>> WM.modify wm (+ 2) (1, 1)+-- >>> WM.prod wm {- x -} 1 3 {- y -} 0 3 -- 1 + 2 + 7 + 6 + 9 + 10+-- Sum {getSum = 35}+--+-- >>> WM.write wm (1, 1) $ Sum 0+-- >>> WM.prod wm {- x -} 1 3 {- y -} 0 3 -- 1 + 2 + 0 + 6 + 9 + 10+-- Sum {getSum = 28}+module AtCoder.Extra.WaveletMatrix2d+ ( -- * Wavelet matrix 2D+ WaveletMatrix2d (..),++ -- * Counstructor+ new,+ build,++ -- * Segment tree methods+ read,+ write,+ modify,+ prod,+ prodMaybe,+ allProd,+ -- wavelet matrix methods could be implemented, too+ )+where++import AtCoder.Extra.Bisect (bisectR, lowerBound)+import AtCoder.Extra.WaveletMatrix.BitVector qualified as BV+import AtCoder.Extra.WaveletMatrix.Raw qualified as Rwm+import AtCoder.Internal.Assert qualified as ACIA+import AtCoder.SegTree qualified as ST+import Control.Monad.Primitive (PrimMonad, PrimState)+import Data.Bit (Bit (..))+import Data.Bits (Bits (testBit))+import Data.Maybe (fromJust, fromMaybe)+import Data.Vector qualified as V+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Generic qualified as VG+import Data.Vector.Unboxed qualified as VU+import GHC.Stack (HasCallStack)+import Prelude hiding (read)++-- NOTE: There are many possible improvements.+-- - Use cumulative sum or fenwick tree instead for the speed.+-- - The inverse operator is not actually required.+-- - Wavelet matrix methods such as `rank` can be implemented+-- - `maxRight` can be implemented.++-- | Segment Tree on Wavelet Matrix: points on a 2D plane and rectangle products.+data WaveletMatrix2d s a = WaveletMatrix2d+ { -- | The wavelet matrix that represents points on a 2D plane.+ rawWmWm2d :: !Rwm.RawWaveletMatrix,+ -- | (x, y) index compression dictionary.+ xyDictWm2d :: !(VU.Vector (Int, Int)),+ -- | y index compression dictionary.+ yDictWm2d :: !(VU.Vector Int),+ -- | The segment tree of the weights of the points in the order of `xyDictWm2d`.+ segTreesWm2d :: !(V.Vector (ST.SegTree s a)),+ -- | The inverse operator of the interested monoid.+ invWm2d :: !(a -> a)+ }++-- | \(O(n \log n)\) Creates a `WaveletMatrix2d` with `mempty` as the initial monoid+-- values for each point.+{-# INLINE new #-}+new ::+ (PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | Inverse operator of the monoid+ (a -> a) ->+ -- | Input points+ VU.Vector (Int, Int) ->+ -- | A 2D wavelet matrix+ m (WaveletMatrix2d (PrimState m) a)+new invWm2d xys = do+ let n = VG.length xys+ let xyDictWm2d = VU.uniq . VU.modify (VAI.sortBy compare) $ xys+ let (!_, !ys) = VU.unzip xys+ let yDictWm2d = VU.uniq $ VU.modify (VAI.sortBy compare) ys+ -- REMARK: Be sure to use `n + 1` because the product function cannot handle the case+ -- `yUpper` is `2^{height}`.+ let (!_, !ysInput) = VU.unzip xyDictWm2d+ let rawWmWm2d = Rwm.build (n + 1) $ VU.map (fromJust . lowerBound yDictWm2d) ysInput+ segTreesWm2d <- V.replicateM (Rwm.heightRwm rawWmWm2d) (ST.new n)+ pure WaveletMatrix2d {..}++-- | \(O(n \log n)\) Creates a `WaveletMatrix2d` with wavelet matrix with segment tree+-- with initial monoid values. Monoids on a duplicate point are accumulated with `(<>)`.+{-# INLINE build #-}+build ::+ (PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | Inverse operator of the monoid+ (a -> a) ->+ -- | Input points with initial values+ VU.Vector (Int, Int, a) ->+ -- | A 2D wavelet matrix+ m (WaveletMatrix2d (PrimState m) a)+build invWm2d xysw = do+ let (!xs, !ys, !_) = VU.unzip3 xysw+ wm <- new invWm2d $ VU.zip xs ys+ -- not the fastest implementation though+ VU.forM_ xysw $ \(!x, !y, !w) -> do+ modify wm (<> w) (x, y)+ pure wm++-- | \(O(1)\) Returns the monoid value at \((x, y)\).+{-# INLINE read #-}+read :: (HasCallStack, VU.Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> (Int, Int) -> m a+read WaveletMatrix2d {..} (!x, !y) = do+ ST.read (V.head segTreesWm2d) . fromJust $ lowerBound xyDictWm2d (x, y)++-- | \(O(\log^2 n)\) Writes the monoid value at \((x, y)\). Access to unknown points are undefined.+{-# INLINE write #-}+write :: (HasCallStack, Monoid a, VU.Unbox a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> (Int, Int) -> a -> m ()+write WaveletMatrix2d {..} (!x, !y) v = do+ let !i_ = fromJust $ lowerBound xyDictWm2d (x, y)+ V.ifoldM'_+ ( \i iRow (!bits, !seg) -> do+ let !i0 = BV.rank0 bits i+ let !i'+ | unBit $ VG.unsafeIndex (BV.bitsBv bits) i =+ i + Rwm.nZerosRwm rawWmWm2d VG.! iRow - i0+ | otherwise = i0+ ST.write seg i' v+ pure i'+ )+ i_+ $ V.zip (Rwm.bitsRwm rawWmWm2d) segTreesWm2d++-- | \(O(\log^2 n)\) Modifies the monoid value at \((x, y)\). Access to unknown points are+-- undefined.+{-# INLINE modify #-}+modify :: (HasCallStack, Monoid a, VU.Unbox a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> (a -> a) -> (Int, Int) -> m ()+modify WaveletMatrix2d {..} f (!x, !y) = do+ let !i_ = fromJust $ lowerBound xyDictWm2d (x, y)+ V.ifoldM'_+ ( \i iRow (!bits, !seg) -> do+ let !i0 = BV.rank0 bits i+ let !i'+ | unBit $ VG.unsafeIndex (BV.bitsBv bits) i =+ i + Rwm.nZerosRwm rawWmWm2d VG.! iRow - i0+ | otherwise = i0+ ST.modify seg f i'+ pure i'+ )+ i_+ $ V.zip (Rwm.bitsRwm rawWmWm2d) segTreesWm2d++-- | \(O(\log^2 n)\) Returns the monoid product in \([l, r) \times [y_1, y_2)\).+{-# INLINE prod #-}+prod :: (HasCallStack, VU.Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> Int -> Int -> Int -> Int -> m a+prod wm@WaveletMatrix2d {..} !xl !xr !yl !yr+ | xl' >= xr' || yl' >= yr' = pure mempty+ | otherwise = unsafeProd wm xl' xr' yl' yr'+ where+ (!xDict, !_) = VU.unzip xyDictWm2d+ -- NOTE: clamping here!+ xl' = fromMaybe 0 $ bisectR 0 (VG.length xDict) $ (< xl) . VG.unsafeIndex xDict+ xr' = fromMaybe (VG.length xDict) $ bisectR 0 (VG.length xDict) $ (< xr) . VG.unsafeIndex xDict+ yl' = fromMaybe 0 $ bisectR 0 (VG.length yDictWm2d) $ (< yl) . VG.unsafeIndex yDictWm2d+ yr' = fromMaybe (VG.length yDictWm2d) $ bisectR 0 (VG.length yDictWm2d) $ (< yr) . VG.unsafeIndex yDictWm2d+ !_ = ACIA.checkInterval "AtCoder.Extra.WaveletMatrix.SegTree.prod (compressed x)" xl' xr' (VG.length xDict)+ !_ = ACIA.checkInterval "AtCoder.Extra.WaveletMatrix.SegTree.prod (compressed y)" yl' yr' (VG.length yDictWm2d)++-- | \(O(\log^2 n)\) Returns the monoid product in \([l, r) \times [y_1, y_2)\). Returns `Nothing` for invalid+-- intervals.+{-# INLINE prodMaybe #-}+prodMaybe :: (VU.Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> Int -> Int -> Int -> Int -> m (Maybe a)+prodMaybe wm@WaveletMatrix2d {..} !xl !xr !yl !yr+ | not (ACIA.testInterval xl' xr' (VG.length xDict)) = pure Nothing+ | not (ACIA.testInterval yl' yr' (VG.length yDictWm2d)) = pure Nothing+ | xl' >= xr' || yl' >= yr' = pure $ Just mempty+ | otherwise = Just <$> unsafeProd wm xl' xr' yl' yr'+ where+ (!xDict, !_) = VU.unzip xyDictWm2d+ -- NOTE: clamping here!+ xl' = fromMaybe 0 $ bisectR 0 (VG.length xDict) $ (< xl) . VG.unsafeIndex xDict+ xr' = fromMaybe (VG.length xDict) $ bisectR 0 (VG.length xDict) $ (< xr) . VG.unsafeIndex xDict+ yl' = fromMaybe 0 $ bisectR 0 (VG.length yDictWm2d) $ (< yl) . VG.unsafeIndex yDictWm2d+ yr' = fromMaybe (VG.length yDictWm2d) $ bisectR 0 (VG.length yDictWm2d) $ (< yr) . VG.unsafeIndex yDictWm2d++-- | \(O(\log^2 n)\) Return the monoid product of all of the points in the wavelet matrix.+{-# INLINE allProd #-}+allProd :: (HasCallStack, VU.Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> m a+allProd WaveletMatrix2d {..} = do+ -- ST.allProd (V.last segTreesWm2d)+ ST.allProd (V.head segTreesWm2d)++-- | \(O(\log^2 n)\) The input is compressed indices.+{-# INLINE unsafeProd #-}+unsafeProd :: (VU.Unbox a, Monoid a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> Int -> Int -> Int -> Int -> m a+unsafeProd wm xl' xr' yl' yr' = do+ sR <- prodLT wm xl' xr' yr'+ sL <- prodLT wm xl' xr' yl'+ pure $! sR <> invWm2d wm sL++-- | \(O(\log^2 n)\)+{-# INLINE prodLT #-}+prodLT :: (Monoid a, VU.Unbox a, PrimMonad m) => WaveletMatrix2d (PrimState m) a -> Int -> Int -> Int -> m a+prodLT WaveletMatrix2d {..} !l_ !r_ yUpper = do+ (!res, !_, !_) <- do+ V.ifoldM'+ ( \(!acc, !l, !r) !iRow (!bits, !seg) -> do+ let !l0 = BV.rank0 bits l+ !r0 = BV.rank0 bits r+ -- REMARK: The function cannot handle the case yUpper = N = 2^i. See the constructor for+ -- how it's handled and note that l_ and r_ are compressed indices.+ if testBit yUpper (Rwm.heightRwm rawWmWm2d - 1 - iRow)+ then do+ !acc' <- (acc <>) <$> ST.prod seg l0 r0+ let !l' = l + Rwm.nZerosRwm rawWmWm2d VG.! iRow - l0+ let !r' = r + Rwm.nZerosRwm rawWmWm2d VG.! iRow - r0+ pure (acc', l', r')+ else do+ pure (acc, l0, r0)+ )+ (mempty, l_, r_)+ $ V.zip (Rwm.bitsRwm rawWmWm2d) segTreesWm2d+ pure res++-- -- | \(O(\log n)\) Restore the original \(x\) coordinate from a compressed one. Access to unknown+-- -- points are undefined.+-- {-# INLINE indexX #-}+-- indexX :: (HasCallStack) => WaveletMatrix2d s a -> Int -> Int+-- indexX WaveletMatrix2d {xyDictWm2d} x = maybe err (VG.unsafeIndex xDict) $ lowerBound xDict x+-- where+-- (!xDict, !_) = VU.unzip xyDictWm2d+-- err = error $ "AtCoder.Extra.WaveletMatirx.SegTree.indexX: cannot index x (`" ++ show x ++ "`)"++-- -- | \(O(\log n)\) Restore the original \(y\) coordinate from a compressed one. Access to unknown+-- -- points are undefined.+-- {-# INLINE indexY #-}+-- indexY :: (HasCallStack) => WaveletMatrix2d s a -> Int -> Int+-- indexY WaveletMatrix2d {yDictWm2d} y = maybe err (VG.unsafeIndex yDictWm2d) $ lowerBound yDictWm2d y+-- where+-- err = error $ "AtCoder.Extra.WaveletMatirx.SegTree.indexY: cannot index y (`" ++ show y ++ "`)"++-- -- | \(O(\log n)\) Restore the original \((x, y)\) coordinates from a compressed one. Access to+-- -- unknown points are undefined.+-- {-# INLINE indexXY #-}+-- indexXY :: (HasCallStack) => WaveletMatrix2d s a -> Int -> Int -> (Int, Int)+-- indexXY WaveletMatrix2d {xyDictWm2d} x y = maybe err (VG.unsafeIndex xyDictWm2d) $ lowerBound xyDictWm2d (x, y)+-- where+-- err = error $ "AtCoder.Extra.WaveletMatirx.SegTree.indexXY: cannot index (x, y) `" ++ show (x, y) ++ "`"++-- {-# INLINE assocsWith #-}+-- assocsWith :: WaveletMatrix -> (Int -> Int) -> [(Int, Int)]+-- assocsWith WaveletMatrix {..} l_ r_ f
src/AtCoder/FenwickTree.hs view
@@ -1,13 +1,13 @@ {-# LANGUAGE RecordWildCards #-} --- | Fenwick tree, also known as binary index tree. Given an array of length \(n\), it processes the--- following queries in \(O(\log n)\) time.+-- | A Fenwick tree, also known as binary indexed tree. Given an array of length \(n\), it processes+-- the following queries in \(O(\log n)\) time. -- -- - Updating an element -- - Calculating the sum of the elements of an interval -- -- ==== __Example__--- You can create a `FenwickTree` with `new`:+-- Create a `FenwickTree` with `new`: -- -- >>> import AtCoder.FenwickTree qualified as FT -- >>> ft <- FT.new @_ @Int 4 -- [0, 0, 0, 0]@@ -24,7 +24,7 @@ -- >>> FT.sum ft 0 3 -- 6 ----- You can create a `FenwickTree` with initial values using `build`:+-- Create a `FenwickTree` with initial values using `build`: -- -- >>> ft <- FT.build @_ @Int $ VU.fromList [3, 0, 3, 0] -- >>> FT.add ft 1 2 -- [3, 2, 3, 0]@@ -40,7 +40,7 @@ new, build, - -- * Modifying the Fenwick tree+ -- * Adding add, -- * Accessor@@ -60,7 +60,7 @@ import GHC.Stack (HasCallStack) import Prelude hiding (sum) --- | Fenwick tree.+-- | A Fenwick tree. -- -- @since 1.0.0.0 data FenwickTree s a = FenwickTree@@ -122,7 +122,7 @@ VGM.modify dataFt (+ x) (p - 1) loop $! p + (p .&. (-p)) --- | \(O(\log n)\) Calculates the sum in half-open range @[0, r)@.+-- | \(O(\log n)\) Calculates the sum in a half-open interval @[0, r)@. -- -- @since 1.0.0.0 {-# INLINE prefixSum #-}@@ -135,7 +135,7 @@ dx <- VGM.read dataFt (r - 1) inner (acc + dx) (r - r .&. (-r)) --- | Calculates the sum in half-open range \([l, r)\).+-- | Calculates the sum in a half-open interval \([l, r)\). -- -- ==== Constraints -- - \(0 \leq l \leq r \leq n\)@@ -150,8 +150,8 @@ | not (ACIA.testInterval l r nFt) = ACIA.errorInterval "AtCoder.FenwickTree.sum" l r nFt | otherwise = unsafeSum ft l r --- | Total version of `sum`. Calculates the sum in half-open range \([l, r)\). It returns `Nothing`--- if the interval is invalid.+-- | Total variant of `sum`. Calculates the sum in a half-open interval \([l, r)\). It returns+-- `Nothing` if the interval is invalid. -- -- ==== Complexity -- - \(O(\log n)\)
src/AtCoder/Internal/Assert.hs view
@@ -73,7 +73,7 @@ testIndex :: (HasCallStack) => Int -> Int -> Bool testIndex i n = 0 <= i && i < n --- | \(O(1)\) Tests weather \([l, r)\) is a valid interval in \([0, n)\).+-- | \(O(1)\) Tests whether \([l, r)\) is a valid interval in \([0, n)\). -- -- @since 1.0.0.0 {-# INLINE testInterval #-}
src/AtCoder/Internal/Barrett.hs view
@@ -1,7 +1,7 @@ {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE RecordWildCards #-} --- | Fast modular multiplication for `Word32` by barrett reduction.+-- | Fast modular multiplication for `Word32` using barrett reduction. -- Reference: https://en.wikipedia.org/wiki/Barrett_reduction -- -- ==== __Example__@@ -16,10 +16,10 @@ module AtCoder.Internal.Barrett ( -- * Barrett Barrett,- -- * Constructors+ -- * Constructor new32, new64,- -- * Accessors+ -- * Accessor umod, -- * Barrett reduction mulMod,@@ -29,7 +29,7 @@ import Data.WideWord.Word128 (Word128 (..)) import Data.Word (Word32, Word64) --- | Fast modular multiplication by barrett reduction.+-- | Fast modular multiplication using barrett reduction. -- Reference: https://en.wikipedia.org/wiki/Barrett_reduction -- -- @since 1.0.0.0@@ -44,14 +44,14 @@ Show ) --- | Creates barret reduction for modulus \(m\) from a `Word32` value.+-- | Creates a `Barrett` for a modulus value \(m\) of type `Word32` value. -- -- @since 1.0.0.0 {-# INLINE new32 #-} new32 :: Word32 -> Barrett new32 m = Barrett m $ maxBound @Word64 `div` (fromIntegral m :: Word64) + 1 --- | Creates barret reduction for modulus \(m\) from a `Word64` value.+-- | Creates a `Barrett` for a modulus value \(m\) of type `Word64` value. -- -- @since 1.0.0.0 {-# INLINE new64 #-}
src/AtCoder/Internal/Buffer.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE RecordWildCards #-} --- | Pushable vector with fixed size capacity. Stack. Internally it tracks the number of elements--- in the vector.+-- | A pushable vector with fixed capacity \(n\). Internally, it tracks the number of elements. -- -- ==== __Example__ -- Create a buffer with capacity @4@:@@ -54,25 +53,21 @@ new, build, - -- * Push/pop- pushBack,- popBack,+ -- * Metadata+ capacity,+ length,+ null, - -- * Inspection+ -- * Reading back,-- -- * Accessing individual elements read,++ -- * Modifications+ pushBack,+ popBack, write, modify, modifyM,-- -- * Accesssors- capacity,- length,- null,-- -- * Clearing clear, -- * Conversions@@ -89,7 +84,7 @@ import GHC.Stack (HasCallStack) import Prelude hiding (length, null, read) --- | Pushable vector with fixed size capacity. Stack.+-- | A pushable vector with fixed capacity \(n\). Internally, it tracks the number of elements. -- -- @since 1.0.0.0 data Buffer s a = Buffer@@ -117,30 +112,28 @@ vecB <- VU.thaw xs pure Buffer {..} --- | \(O(1)\) Appends an element to the back.+-- | \(O(1)\) Returns the array size. -- -- @since 1.0.0.0-{-# INLINE pushBack #-}-pushBack :: (HasCallStack, PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> a -> m ()-pushBack Buffer {..} e = do- len <- VGM.read lenB 0- VGM.write vecB len e- VGM.write lenB 0 (len + 1)+{-# INLINE capacity #-}+capacity :: (VU.Unbox a) => Buffer s a -> Int+capacity = VUM.length . vecB --- | \(O(1)\) Removes the last element from the buffer and returns it, or `Nothing` if it is empty.+-- | \(O(1)\) Returns the number of elements in the buffer. -- -- @since 1.0.0.0-{-# INLINE popBack #-}-popBack :: (PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> m (Maybe a)-popBack Buffer {..} = do- len <- VGM.read lenB 0- if len == 0- then pure Nothing- else do- x <- VGM.read vecB (len - 1)- VGM.write lenB 0 (len - 1)- pure $ Just x+{-# INLINE length #-}+length :: (PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> m Int+length Buffer {..} = do+ VGM.read lenB 0 +-- | \(O(1)\) Returns `True` if the buffer is empty.+--+-- @since 1.0.0.0+{-# INLINE null #-}+null :: (PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> m Bool+null = (<$>) (== 0) . length+ -- | \(O(1)\) Returns the last value in the buffer, or `Nothing` if it is empty. -- -- @since 1.0.0.0@@ -165,8 +158,32 @@ let !_ = ACIA.checkIndex "AtCoder.Internal.Buffer.read" i len VGM.read vecB i +-- | \(O(1)\) Appends an element to the back.+--+-- @since 1.0.0.0+{-# INLINE pushBack #-}+pushBack :: (HasCallStack, PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> a -> m ()+pushBack Buffer {..} e = do+ len <- VGM.read lenB 0+ VGM.write vecB len e+ VGM.write lenB 0 (len + 1)++-- | \(O(1)\) Removes the last element from the buffer and returns it, or `Nothing` if it is empty.+--+-- @since 1.0.0.0+{-# INLINE popBack #-}+popBack :: (PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> m (Maybe a)+popBack Buffer {..} = do+ len <- VGM.read lenB 0+ if len == 0+ then pure Nothing+ else do+ x <- VGM.read vecB (len - 1)+ VGM.write lenB 0 (len - 1)+ pure $ Just x+ -- | \(O(1)\) Writes to the element at the given position. Will throw an exception if the index is--- out of range.+-- out of bounds. -- -- @since 1.0.0.0 {-# INLINE write #-}@@ -177,7 +194,7 @@ VGM.write vecB i e -- | \(O(1)\) Writes to the element at the given position. Will throw an exception if the index is--- out of range.+-- out of bounds. -- -- @since 1.0.0.0 {-# INLINE modify #-}@@ -188,7 +205,7 @@ VGM.modify vecB f i -- | \(O(1)\) Writes to the element at the given position. Will throw an exception if the index is--- out of range.+-- out of bounds. -- -- @since 1.0.0.0 {-# INLINE modifyM #-}@@ -197,28 +214,6 @@ len <- VGM.read lenB 0 let !_ = ACIA.checkIndex "AtCoder.Internal.Buffer.modifyM" i len VGM.modifyM vecB f i---- | \(O(1)\) Returns the array size.------ @since 1.0.0.0-{-# INLINE capacity #-}-capacity :: (VU.Unbox a) => Buffer s a -> Int-capacity = VUM.length . vecB---- | \(O(1)\) Returns the number of elements in the buffer.------ @since 1.0.0.0-{-# INLINE length #-}-length :: (PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> m Int-length Buffer {..} = do- VGM.read lenB 0---- | \(O(1)\) Returns `True` if the buffer is empty.------ @since 1.0.0.0-{-# INLINE null #-}-null :: (PrimMonad m, VU.Unbox a) => Buffer (PrimState m) a -> m Bool-null = (<$>) (== 0) . length -- | \(O(1)\) Sets the `length` to zero. --
src/AtCoder/Internal/Convolution.hs view
@@ -55,7 +55,7 @@ Show ) --- | \(O(\log m)\) Creates `FftInfo`.+-- | \(O(\log m)\) Creates an `FftInfo`. -- -- @since 1.0.0.0 {-# INLINE newInfo #-}
src/AtCoder/Internal/Csr.hs view
@@ -1,9 +1,10 @@ {-# LANGUAGE RecordWildCards #-} --- | Immutable Compresed Sparse Row.+-- | Immutable Compresed Sparse Row. It is re-exported from the @AtCoder.Extra.Graph@ module with+-- additional functionalities. -- -- ==== __Example__--- Create a `Csr` without edge weights using `build`:+-- Create a `Csr` without edge weights using `build'` and retrieve the edges with `adj`: -- -- >>> import AtCoder.Internal.Csr qualified as C -- >>> let csr = build' 3 $ VU.fromList @(Int, Int) [(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]@@ -16,7 +17,7 @@ -- >>> csr `C.adj` 2 -- [3] ----- Create a `Csr` with edge weights with `build` and retrieve edge with `edgeW`:+-- Create a `Csr` with edge weights using `build` and retrieve the edges with `adjW`: -- -- >>> import AtCoder.Internal.Csr qualified as C -- >>> let csr = build 3 $ VU.fromList @(Int, Int, Int) [(0, 1, 101), (0, 2, 102), (0, 3, 103), (1, 2, 112), (2, 3, 123)]@@ -32,10 +33,13 @@ -- @since 1.0.0.0 module AtCoder.Internal.Csr ( -- * Compressed sparse row- Csr,+ Csr (..),+ -- * Constructor build, build',+ build1,+ -- * Accessors adj, adjW,@@ -55,8 +59,25 @@ -- -- @since 1.0.0.0 data Csr w = Csr- { startCsr :: !(VU.Vector Int),+ { -- | The number of vertices.+ --+ -- @since 1.1.0.0+ nCsr :: {-# UNPACK #-} !Int,+ -- | The number of edges.+ --+ -- @since 1.1.0.0+ mCsr :: {-# UNPACK #-} !Int,+ -- | Starting indices.+ --+ -- @since 1.1.0.0+ startCsr :: !(VU.Vector Int),+ -- | Adjacent vertices.+ --+ -- @since 1.1.0.0 adjCsr :: !(VU.Vector Int),+ -- | Edge weights.+ --+ -- @since 1.1.0.0 wCsr :: !(VU.Vector w) } deriving@@ -66,25 +87,26 @@ Show ) --- | \(O(n + m)\) Creates `Csr`.+-- | \(O(n + m)\) Creates a `Csr`. -- -- @since 1.0.0.0 {-# INLINE build #-} build :: (HasCallStack, VU.Unbox w) => Int -> VU.Vector (Int, Int, w) -> Csr w-build n edges = runST $ do- start <- VUM.replicate (n + 1) (0 :: Int)+build nCsr edges = runST $ do+ let mCsr = VU.length edges+ start <- VUM.replicate (nCsr + 1) (0 :: Int) let (!froms, !_, !_) = VU.unzip3 edges VU.forM_ froms $ \from -> do VGM.modify start (+ 1) (from + 1) - for_ [1 .. n] $ \i -> do+ for_ [1 .. nCsr] $ \i -> do prev <- VGM.read start (i - 1) VGM.modify start (+ prev) i edgeAdj <- VUM.unsafeNew (VU.length edges) edgeW <- VUM.unsafeNew (VU.length edges)- counter <- VUM.unsafeNew n+ counter <- VUM.unsafeNew nCsr VUM.unsafeCopy counter $ VUM.init start VU.forM_ edges $ \(!from, !to, !w) -> do c <- VGM.read counter from@@ -97,7 +119,7 @@ wCsr <- VU.unsafeFreeze edgeW pure Csr {..} --- | \(O(n + m)\) Creates `Csr` with no weight.+-- | \(O(n + m)\) Creates a `Csr` with no edge weight. -- -- @since 1.0.0.0 {-# INLINE build' #-}@@ -106,17 +128,26 @@ where (!us, !vs) = VU.unzip edges --- | \(O(1)\) Returns adjacent vertices.+-- | \(O(n + m)\) Creates a `Csr` with @1@ as edge weights. --+-- @since 1.1.0.0+{-# INLINE build1 #-}+build1 :: (HasCallStack) => Int -> VU.Vector (Int, Int) -> Csr Int+build1 n edges = build n $ VU.zip3 us vs (VU.replicate (VU.length us) (1 :: Int))+ where+ (!us, !vs) = VU.unzip edges++-- | \(O(1)\) Returns the adjacent vertices.+-- -- @since 1.0.0.0 {-# INLINE adj #-}-adj :: (HasCallStack, VU.Unbox w) => Csr w -> Int -> VU.Vector Int+adj :: (HasCallStack) => Csr w -> Int -> VU.Vector Int adj Csr {..} i = let il = startCsr VG.! i ir = startCsr VG.! (i + 1) in VU.slice il (ir - il) adjCsr --- | \(O(1)\) Returns adjacent vertices with weights.+-- | \(O(1)\) Returns the adjacent vertices with weights. -- -- @since 1.0.0.0 {-# INLINE adjW #-}@@ -126,11 +157,11 @@ ir = startCsr VG.! (i + 1) in VU.zip (VU.slice il (ir - il) adjCsr) (VU.slice il (ir - il) wCsr) --- | \(O(1)\) Returns a vector of @(edgeId, adjacentVertex)@.+-- | \(O(n)\) Returns a vector of @(edgeId, adjacentVertex)@. -- -- @since 1.0.0.0 {-# INLINE eAdj #-}-eAdj :: (HasCallStack, VU.Unbox w) => Csr w -> Int -> VU.Vector (Int, Int)+eAdj :: (HasCallStack) => Csr w -> Int -> VU.Vector (Int, Int) eAdj Csr {..} i = let il = startCsr VG.! i ir = startCsr VG.! (i + 1)
src/AtCoder/Internal/GrowVec.hs view
@@ -39,32 +39,32 @@ -- -- @since 1.0.0.0 module AtCoder.Internal.GrowVec- ( -- * Growable vector+ ( -- * GrowVec GrowVec (vecGV), - -- * Constructions-- -- ** Initialization+ -- * Constructors new, build,-- -- ** Reserving reserve, - -- * Accessing individual elements+ -- * Metadata+ length,+ capacity,+ null,++ -- * Readings read,++ -- * Modifications++ -- ** Writing write, - -- * Modifying the buffer+ -- ** Push/pop pushBack, popBack, popBack_, - -- * Accessors- length,- capacity,- null,- -- * Conversion freeze, unsafeFreeze,@@ -91,7 +91,7 @@ vecGV :: !(MutVar s (VUM.MVector s a)) } --- | \(O(n)\) Creates `GrowVec` with initial capacity \(n\).+-- | \(O(n)\) Creates a `GrowVec` with initial capacity \(n\). -- -- @since 1.0.0.0 {-# INLINE new #-}@@ -101,7 +101,7 @@ vecGV <- newMutVar =<< VUM.unsafeNew n pure GrowVec {..} --- | \(O(n)\) Creates `GrowVec` with initial values.+-- | \(O(n)\) Creates a `GrowVec` with initial values. -- -- @since 1.0.0.0 {-# INLINE build #-}@@ -122,6 +122,30 @@ newVec <- VUM.unsafeGrow vec (len - VUM.length vec) writeMutVar vecGV newVec +-- | \(O(1)\) Returns the number of elements in the vector.+--+-- @since 1.0.0.0+{-# INLINE length #-}+length :: (PrimMonad m, VU.Unbox a) => GrowVec (PrimState m) a -> m Int+length GrowVec {posGV} = do+ VGM.unsafeRead posGV 0++-- | \(O(1)\) Returns the capacity of the internal the vector.+--+-- @since 1.0.0.0+{-# INLINE capacity #-}+capacity :: (PrimMonad m, VU.Unbox a) => GrowVec (PrimState m) a -> m Int+capacity GrowVec {vecGV} = do+ vec <- readMutVar vecGV+ pure $ VUM.length vec++-- | \(O(1)\) Returns `True` if the vector is empty.+--+-- @since 1.0.0.0+{-# INLINE null #-}+null :: (PrimMonad m, VU.Unbox a) => GrowVec (PrimState m) a -> m Bool+null = (<$>) (== 0) . length+ -- | \(O(1)\) Yields the element at the given position. Will throw an exception if the index is out -- of range. --@@ -185,7 +209,7 @@ vec <- readMutVar vecGV Just <$> VGM.read vec (pos - 1) --- | \(O(1)\) `popBack` with return value discarded.+-- | \(O(1)\) `popBack` with the return value discarded. -- -- @since 1.0.0.0 {-# INLINE popBack_ #-}@@ -193,30 +217,6 @@ popBack_ GrowVec {..} = do pos <- VGM.unsafeRead posGV 0 VGM.unsafeWrite posGV 0 $ max 0 $ pos - 1---- | \(O(1)\) Returns the number of elements in the vector.------ @since 1.0.0.0-{-# INLINE length #-}-length :: (PrimMonad m, VU.Unbox a) => GrowVec (PrimState m) a -> m Int-length GrowVec {posGV} = do- VGM.unsafeRead posGV 0---- | \(O(1)\) Returns the capacity of the internal the vector.------ @since 1.0.0.0-{-# INLINE capacity #-}-capacity :: (PrimMonad m, VU.Unbox a) => GrowVec (PrimState m) a -> m Int-capacity GrowVec {vecGV} = do- vec <- readMutVar vecGV- pure $ VUM.length vec---- | \(O(1)\) Returns `True` if the vector is empty.------ @since 1.0.0.0-{-# INLINE null #-}-null :: (PrimMonad m, VU.Unbox a) => GrowVec (PrimState m) a -> m Bool-null = (<$>) (== 0) . length -- | \(O(n)\) Yields an immutable copy of the mutable vector. --
src/AtCoder/Internal/Math.hs view
@@ -64,7 +64,16 @@ -- -- @since 1.0.0.0 {-# INLINE powMod #-}-powMod :: (HasCallStack) => Int -> Int -> Int -> Int+powMod ::+ (HasCallStack) =>+ -- | \(x\)+ Int ->+ -- | \(n\)+ Int ->+ -- | \(m\)+ Int ->+ -- | \(x^n \bmod m\)+ Int powMod x n0 m0 | m0 == 1 = 0 | otherwise = fromIntegral $ inner n0 1 $ fromIntegral (x `mod` m0)@@ -81,6 +90,13 @@ -- | M. Forisek and J. Jancina, Fast Primality Testing for Integers That Fit into a Machine Word --+-- ==== Constraints+-- - \(n < 4759123141 (2^{32} < 4759123141)\), otherwise the return value can lie+-- ([Wikipedia](https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Testing_against_small_sets_of_bases)).+--+-- ==== Complexity+-- - \(O(k \log^3 n)\), \(k = 3\)+-- -- @since 1.0.0.0 {-# INLINE isPrime #-} isPrime :: Int -> Bool@@ -100,7 +116,7 @@ | t == n - 1 || y == 1 || y == n - 1 = not $ y /= n - 1 && even t | otherwise = inner (t .<<. 1) (y * y `mod` n) --- | Returns \((g, x)\) such that \(g = \gcd(a, b), \mathrm{xa} = g(\bmod b), 0 \le x \le b/g\).+-- | Returns \((g, x)\) such that \(g = \gcd(a, b), \mathrm{xa} \equiv g \pmod b, 0 \le x \le b/g\). -- -- ==== Constraints -- - \(1 \le b\) (not asserted)@@ -128,7 +144,7 @@ !m0' = m0 - m1 * u in inner t s' m1 m0' --- | Returns primitive root.+-- | Returns the primitive root of the given `Int`. -- -- @since 1.0.0.0 {-# INLINE primitiveRoot #-}
src/AtCoder/Internal/MinHeap.hs view
@@ -34,22 +34,22 @@ ( -- * Heap Heap, - -- * Constructor+ -- * Constructors new, - -- * Accessors+ -- * Metadata capacity, length, null, - -- * Accessors+ -- * Reset clear, - -- * Modifying the heap+ -- * Push/pop/peek push,- peek, pop, pop_,+ peek, ) where @@ -81,7 +81,7 @@ dataBH :: !(VUM.MVector s a) } --- | \(O(n)\) Creates `Heap` with capacity \(n\).+-- | \(O(n)\) Creates a `Heap` with capacity \(n\). -- -- @since 1.0.0.0 {-# INLINE new #-}@@ -136,17 +136,6 @@ siftUp iParent siftUp i0 --- | \(O(1)\) Returns the smallest value in the heap, or `Nothing` if it is empty.------ @since 1.0.0.0-{-# INLINE peek #-}-peek :: (VU.Unbox a, PrimMonad m) => Heap (PrimState m) a -> m (Maybe a)-peek heap = do- isNull <- null heap- if isNull- then pure Nothing- else Just <$> VGM.read (dataBH heap) 0- -- | \(O(\log n)\) Removes the last element from the heap and returns it, or `Nothing` if it is -- empty. --@@ -189,7 +178,7 @@ siftDown 0 pure $ Just root --- | \(O(\log n)\) `pop` with return value discarded.+-- | \(O(\log n)\) `pop` with the return value discarded. -- -- @since 1.0.0.0 {-# INLINE pop_ #-}@@ -197,3 +186,14 @@ pop_ heap = do _ <- pop heap pure ()++-- | \(O(1)\) Returns the smallest value in the heap, or `Nothing` if it is empty.+--+-- @since 1.0.0.0+{-# INLINE peek #-}+peek :: (VU.Unbox a, PrimMonad m) => Heap (PrimState m) a -> m (Maybe a)+peek heap = do+ isNull <- null heap+ if isNull+ then pure Nothing+ else Just <$> VGM.read (dataBH heap) 0
src/AtCoder/Internal/Queue.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE RecordWildCards #-} --- | Fixed-sized queue. Internally it has \(l, r\) pair of valid element bounds.+-- | Fixed-sized queue. Internally it has an \([l, r)\) pair of valid element bounds. -- -- ==== __Example__ -- >>> import AtCoder.Internal.Queue qualified as Q@@ -43,18 +43,20 @@ -- * Constructor new, - -- * Modifying the queue+ -- * Metadata+ capacity,+ length,+ null,++ -- * Modifications++ -- ** Push/pop pushBack, pushFront, popFront, popFront_, - -- * Accessors- capacity,- length,- null,-- -- * Clearing+ -- ** Reset clear, -- * Conversions@@ -70,7 +72,7 @@ import GHC.Stack (HasCallStack) import Prelude hiding (length, null) --- | Fixed-sized queue. Internally it has \([l, r)\) pair of valid element bounds.+-- | Fixed-sized queue. Internally it has an \([l, r)\) pair of valid element bounds. -- -- @since 1.0.0.0 data Queue s a = Queue@@ -79,7 +81,7 @@ vecQ :: !(VUM.MVector s a) } --- | \(O(n)\) Creates `Queue` with capacity \(n\).+-- | \(O(n)\) Creates a `Queue` with capacity \(n\). -- -- @since 1.0.0.0 {-# INLINE new #-}@@ -89,6 +91,30 @@ vecQ <- VUM.unsafeNew n pure Queue {..} +-- | \(O(1)\) Returns the array size.+--+-- @since 1.0.0.0+{-# INLINE capacity #-}+capacity :: (VU.Unbox a) => Queue s a -> Int+capacity = VUM.length . vecQ++-- | \(O(1)\) Returns the number of elements in the queue.+--+-- @since 1.0.0.0+{-# INLINE length #-}+length :: (PrimMonad m, VU.Unbox a) => Queue (PrimState m) a -> m Int+length Queue {..} = do+ l <- VGM.unsafeRead posQ 0+ r <- VGM.unsafeRead posQ 1+ pure $ r - l++-- | \(O(1)\) Returns `True` if the buffer is empty.+--+-- @since 1.0.0.0+{-# INLINE null #-}+null :: (PrimMonad m, VU.Unbox a) => Queue (PrimState m) a -> m Bool+null = (<$>) (== 0) . length+ -- | \(O(1)\) Appends an element to the back. Will throw an exception if the index is out of range. -- -- @since 1.0.0.0@@ -136,7 +162,7 @@ VGM.unsafeWrite posQ 0 (l + 1) pure $ Just x --- | \(O(1)\) `popFront` with return value discarded.+-- | \(O(1)\) `popFront` with the return value discarded. -- -- @since 1.0.0.0 {-# INLINE popFront_ #-}@@ -144,30 +170,6 @@ popFront_ que = do _ <- popFront que pure ()---- | \(O(1)\) Returns the array size.------ @since 1.0.0.0-{-# INLINE capacity #-}-capacity :: (VU.Unbox a) => Queue s a -> Int-capacity = VUM.length . vecQ---- | \(O(1)\) Returns the number of elements in the queue.------ @since 1.0.0.0-{-# INLINE length #-}-length :: (PrimMonad m, VU.Unbox a) => Queue (PrimState m) a -> m Int-length Queue {..} = do- l <- VGM.unsafeRead posQ 0- r <- VGM.unsafeRead posQ 1- pure $ r - l---- | \(O(1)\) Returns `True` if the buffer is empty.------ @since 1.0.0.0-{-# INLINE null #-}-null :: (PrimMonad m, VU.Unbox a) => Queue (PrimState m) a -> m Bool-null = (<$>) (== 0) . length -- | \(O(1)\) Sets the `length` to zero. --
src/AtCoder/Internal/Scc.hs view
@@ -8,15 +8,19 @@ ( -- * Internal SCC SccGraph (nScc), - -- * Constructor+ -- * Constructors new, - -- * Modifying the graph+ -- * Adding edges addEdge, -- * SCC calculation sccIds, scc,++ -- ** (Extra API) CSR API+ sccIdsCsr,+ sccCsr ) where @@ -25,6 +29,7 @@ import Control.Monad (unless, when) import Control.Monad.Fix (fix) import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (runST) import Data.Foldable (for_) import Data.Maybe (fromJust) import Data.Vector qualified as V@@ -44,7 +49,7 @@ edgesScc :: !(ACIGV.GrowVec s (Int, Int)) } --- | \(O(n)\) Creates `SccGraph` of \(n\) vertices.+-- | \(O(n)\) Creates a `SccGraph` of \(n\) vertices. -- -- @since 1.0.0.0 {-# INLINE new #-}@@ -67,19 +72,47 @@ {-# INLINE sccIds #-} sccIds :: (PrimMonad m) => SccGraph (PrimState m) -> m (Int, VU.Vector Int) sccIds SccGraph {..} = do+ csr <- ACICSR.build' nScc <$> ACIGV.unsafeFreeze edgesScc+ pure $ sccIdsCsr csr++-- | \(O(n + m)\) Returns the strongly connected components.+--+-- @since 1.0.0.0+{-# INLINE scc #-}+scc :: (PrimMonad m) => SccGraph (PrimState m) -> m (V.Vector (VU.Vector Int))+scc g = do+ (!groupNum, !ids) <- sccIds g+ let counts = VU.create $ do+ vec <- VUM.replicate groupNum (0 :: Int)+ VU.forM_ ids $ \x -> do+ VGM.modify vec (+ 1) x+ pure vec+ groups <- V.mapM VUM.unsafeNew $ VU.convert counts+ is <- VUM.replicate groupNum (0 :: Int)+ VU.iforM_ ids $ \v sccId -> do+ i <- VGM.read is sccId+ VGM.write is sccId $ i + 1+ VGM.write (groups VG.! sccId) i v+ V.mapM VU.unsafeFreeze groups++-- | \(O(n + m)\) API) Returns a pair of @(# of scc, scc id)@.+--+-- @since 1.1.0.0+{-# INLINE sccIdsCsr #-}+sccIdsCsr :: ACICSR.Csr w -> (Int, VU.Vector Int)+sccIdsCsr g@ACICSR.Csr {..} = runST $ do -- see also the Wikipedia: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm#The_algorithm_in_pseudocode- g <- ACICSR.build' nScc <$> ACIGV.unsafeFreeze edgesScc -- next SCC ID groupNum <- VUM.replicate 1 (0 :: Int) -- stack of vertices- visited <- ACIGV.new nScc+ visited <- ACIGV.new nCsr -- vertex -> low-link: the smallest index of any node on the stack known to be reachable from -- v through v's DFS subtree, including v itself.- low <- VUM.replicate nScc (0 :: Int)+ low <- VUM.replicate nCsr (0 :: Int) -- vertex -> order of the visit (0, 1, ..)- ord <- VUM.replicate nScc (-1 :: Int)+ ord <- VUM.replicate nCsr (-1 :: Int) -- vertex -> scc id- ids <- VUM.replicate nScc (0 :: Int)+ ids <- VUM.replicate nCsr (0 :: Int) let dfs v ord0 = do VGM.write low v ord0@@ -112,7 +145,7 @@ sccId <- VGM.unsafeRead groupNum 0 fix $ \loop -> do u <- fromJust <$> ACIGV.popBack visited- VGM.write ord u nScc+ VGM.write ord u nCsr VGM.write ids u sccId unless (u == v) loop VGM.unsafeWrite groupNum 0 $ sccId + 1@@ -126,12 +159,12 @@ else pure curOrd ) (0 :: Int)- (VU.generate nScc id)+ (VU.generate nCsr id) num <- VGM.unsafeRead groupNum 0 -- The SCCs are reverse topologically sorted, e.g., [0, 1] <- [2] <- [3] -- Now reverse the SCC IDs so that they will be topologically sorted: [3] -> [2] -> [0, 1]- for_ [0 .. nScc - 1] $ \i -> do+ for_ [0 .. nCsr - 1] $ \i -> do VGM.modify ids ((num - 1) -) i ids' <- VU.unsafeFreeze ids@@ -139,16 +172,10 @@ -- | \(O(n + m)\) Returns the strongly connected components. ----- @since 1.0.0.0-{-# INLINE scc #-}-scc :: (PrimMonad m) => SccGraph (PrimState m) -> m (V.Vector (VU.Vector Int))-scc g = do- (!groupNum, !ids) <- sccIds g- let counts = VU.create $ do- vec <- VUM.replicate groupNum (0 :: Int)- VU.forM_ ids $ \x -> do- VGM.modify vec (+ 1) x- pure vec+-- @since 1.1.0.0+{-# INLINE sccCsr #-}+sccCsr :: ACICSR.Csr w -> V.Vector (VU.Vector Int)+sccCsr g = runST $ do groups <- V.mapM VUM.unsafeNew $ VU.convert counts is <- VUM.replicate groupNum (0 :: Int) VU.iforM_ ids $ \v sccId -> do@@ -156,3 +183,10 @@ VGM.write is sccId $ i + 1 VGM.write (groups VG.! sccId) i v V.mapM VU.unsafeFreeze groups+ where+ (!groupNum, !ids) = sccIdsCsr g+ counts = VU.create $ do+ vec <- VUM.replicate groupNum (0 :: Int)+ VU.forM_ ids $ \x -> do+ VGM.modify vec (+ 1) x+ pure vec
src/AtCoder/Internal/String.hs view
@@ -20,7 +20,7 @@ import Data.Vector.Unboxed.Mutable qualified as VUM import GHC.Stack (HasCallStack) --- TODO: remove `HasCallStack` when we're 100% sure the input is guarded+-- TODO: remove `HasCallStack`? -- | \(O(n^2)\) Internal implementation of suffix array creation (naive). --@@ -88,7 +88,18 @@ -- -- @since 1.0.0.0 {-# INLINE saIsImpl #-}-saIsImpl :: (HasCallStack) => Int -> Int -> VU.Vector Int -> Int -> VU.Vector Int+saIsImpl ::+ (HasCallStack) =>+ -- | naive threshould+ Int ->+ -- | doubling threshould+ Int ->+ -- | string+ VU.Vector Int ->+ -- | upper bounds+ Int ->+ -- | suffix array+ VU.Vector Int saIsImpl naiveThreshold doublingThreshold s upper = VU.create $ do let n = VU.length s let !ls = VU.create $ do@@ -247,7 +258,14 @@ -- -- @since 1.0.0.0 {-# INLINE saIs #-}-saIs :: (HasCallStack) => VU.Vector Int -> Int -> VU.Vector Int+saIs ::+ (HasCallStack) =>+ -- | string+ VU.Vector Int ->+ -- | upper bounds+ Int ->+ -- | suffix array+ VU.Vector Int saIs = saIsManual 10 40 -- | \(O(n)\) Internal implementation of suffix array creation (suffix array induced sorting).@@ -259,7 +277,18 @@ -- -- @since 1.0.0.0 {-# INLINE saIsManual #-}-saIsManual :: (HasCallStack) => Int -> Int -> VU.Vector Int -> Int -> VU.Vector Int+saIsManual ::+ (HasCallStack) =>+ -- | naive threshold+ Int ->+ -- | doubling threshold+ Int ->+ -- | string+ VU.Vector Int ->+ -- | upper bounds+ Int ->+ -- | suffix array+ VU.Vector Int saIsManual naiveThreshold doublingThreshold s upper | n == 0 = VU.empty | n == 1 = VU.singleton 0
src/AtCoder/LazySegTree.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE RecordWildCards #-} --- | Lazily propagted segment tree. It is the data structure for the pair of a [monoid](https://en.wikipedia.org/wiki/Monoid)+-- | A lazily propagted segment tree. It is the data structure for the pair of a [monoid](https://en.wikipedia.org/wiki/Monoid) -- \((S, \cdot: S \times S \to S, e \in S)\) and a set \(F\) of \(S \to S\) mappings that satisfies -- the following properties. --@@ -51,7 +51,7 @@ -- >>> LST.allProd seg -- Sum {getSum = 24} ----- Run binary search in \(O(\log n\) time complexity:+-- Run binary search: -- -- >>> LST.maxRight seg 0 (<= (Sum 10)) -- sum [0, 2) = 7 <= 10 -- 2@@ -59,8 +59,7 @@ -- >>> LST.minLeft seg 4 (<= (Sum 10)) -- sum [3, 4) = 10 <= 10 -- 3 ----- Inspect all the values in \(O(n \log n)\) with `freeze` or `unsafeFreeze`. Note that they--- propagete all the applied actions:+-- Inspect all the values in \(O(n \log n)\) with `freeze` or `unsafeFreeze`: -- -- >>> VU.map getSum <$> LST.freeze seg -- [2,5,7,10]@@ -69,14 +68,14 @@ -- -- - `prod` returns \(a_l \cdot a_{l + 1} \cdot .. \cdot a_{r - 1}\). If you need \(a_{r - 1} \cdot a_{r - 2} \cdot .. \cdot a_{l}\), -- wrap your monoid in `Data.Monoid.Dual`.--- - If you ever need to store boxed types to `LazySegTree`, wrap it in 'vector:Data.Vector.Unboxed.DoNotUnboxStrict'+-- - If you ever need to store boxed types to `LazySegTree`, wrap it in @Data.Vector.Unboxed.DoNotUnboxStrict@ -- or the like. -- -- ==== Major changes from the original @ac-library@ -- - The API is based on `Monoid` and `SegAct`, not the functions @op@, @e@, @mapping@, -- @composition@ and @id@. -- - @get@ and @set@ are renamed to `read` and `write`.--- - `modify`, `modifyM`, `freeze` and `unsafeFreeze` are added.+-- - `modify`, `modifyM`, `exchange`, `freeze` and `unsafeFreeze` are added. -- -- @since 1.0.0.0 module AtCoder.LazySegTree@@ -88,10 +87,11 @@ new, build, - -- * Accessing individual elements+ -- * Accessing elements write, modify, modifyM,+ exchange, read, -- * Products@@ -134,17 +134,19 @@ -- | Typeclass reprentation of the `LazySegTree` properties. User can implement either `segAct` or -- `segActWithLength`. ----- Instances should satisfy the follwing:+-- Instances should satisfy the follwing properties: -- -- [Left monoid action] @'segAct' (f2 '<>' f1) x = 'segAct' f2 ('segAct' f1 x)@ -- [Identity map] @`segAct` `mempty` x = x@ -- [Endomorphism] @'segAct' f (x1 '<>' x2) = ('segAct' f x1) '<>' ('segAct' f x2)@ ----- If you implement `segActWithLength`, satisfy one more propety:+-- If you implement `SegAct` via `segActWithLength`, satisfy one more propety: -- -- [Linear left monoid action] @'segActWithLength' len f a = 'Data.Semigroup.stimes' len ('segAct' f a) a@. ----- Note that in `SegAct` instances, new semigroup values are always given from the left: @new '<>' old@.+-- ==== Invariant+-- In `SegAct` instances, new semigroup values are always given from the left: @new '<>' old@. The+-- order is important for non-commutative monoid implementations. -- -- ==== __Example instance__ -- Take `AtCoder.Extra.Monoid.Affine1` as an example of type \(F\).@@ -287,7 +289,7 @@ segActWithLength :: Int -> f -> a -> a segActWithLength _ = segAct --- | Lazy segment tree defined around `SegAct`.+-- | A lazily propagated segment tree defined around `SegAct`. -- -- @since 1.0.0.0 data LazySegTree s f a = LazySegTree@@ -408,6 +410,27 @@ for_ [1 .. logLst] $ \i -> do update self $ p' .>>. i +-- | (Extra API) Sets \(p\)-th value of the array to \(x\) and returns the old value.+--+-- ==== Constraints+-- - \(0 \leq p \lt n\)+--+-- ==== Complexity+-- - \(O(\log n)\)+--+-- @since 1.1.0.0+{-# INLINE exchange #-}+exchange :: (HasCallStack, PrimMonad m, SegAct f a, VU.Unbox f, Monoid a, VU.Unbox a) => LazySegTree (PrimState m) f a -> Int -> a -> m a+exchange self@LazySegTree {..} p x = do+ let !_ = ACIA.checkIndex "AtCoder.LazySegTree.exchange" p nLst+ let p' = p + sizeLst+ for_ [logLst, logLst - 1 .. 1] $ \i -> do+ push self $ p' .>>. i+ res <- VGM.exchange dLst p' x+ for_ [1 .. logLst] $ \i -> do+ update self $ p' .>>. i+ pure res+ -- | Returns \(p\)-th value of the array. -- -- ==== Constraints@@ -443,8 +466,8 @@ | l0 == r0 = pure mempty | otherwise = unsafeProd self l0 r0 --- | Total version of `prod`. Returns the product of \([a[l], ..., a[r - 1]]\), assuming the--- properties of the monoid. It returns `Just` `mempty` if \(l = r\). It returns `Nothing` if the+-- | Total variant of `prod`. Returns the product of \([a[l], ..., a[r - 1]]\), assuming the+-- properties of the monoid. Returns `Just` `mempty` if \(l = r\). It returns `Nothing` if the -- interval is invalid. -- -- ==== Complexity@@ -494,7 +517,7 @@ allProd :: (PrimMonad m, Monoid a, VU.Unbox a) => LazySegTree (PrimState m) f a -> m a allProd LazySegTree {..} = VGM.read dLst 1 --- | Applies @segAct f@ to an index @p@.+-- | Applies @segAct f@ to an index \(p\). -- -- ==== Constraints -- - \(0 \leq p \lt n\)@@ -517,7 +540,7 @@ for_ [1 .. logLst] $ \i -> do update self $ p' .>>. i --- | Applies @segAct f@ to an interval @[l, r)@.+-- | Applies @segAct f@ to an interval \([l, r)\). -- -- ==== Constraints -- - \(0 \leq l \leq r \leq n\)@@ -577,7 +600,7 @@ minLeft :: (HasCallStack, PrimMonad m, SegAct f a, VU.Unbox f, Monoid a, VU.Unbox a) => LazySegTree (PrimState m) f a -> Int -> (a -> Bool) -> m Int minLeft seg r0 g = minLeftM seg r0 (pure . g) --- | Monadic version of `minLeft`.+-- | Monadic variant of `minLeft`. -- -- ==== Constraints --@@ -652,7 +675,7 @@ maxRight :: (HasCallStack, PrimMonad m, SegAct f a, VU.Unbox f, Monoid a, VU.Unbox a) => LazySegTree (PrimState m) f a -> Int -> (a -> Bool) -> m Int maxRight seg l0 g = maxRightM seg l0 (pure . g) --- | Monadic version of `maxRight`.+-- | Monadic variant of `maxRight`. -- -- ==== Constraints --
src/AtCoder/Math.hs view
@@ -5,6 +5,7 @@ -- @since 1.0.0.0 module AtCoder.Math ( -- * Modulus operations+ -- These functions are internally used for `AtCoder.ModInt`. powMod, invMod,@@ -42,7 +43,14 @@ -- -- @since 1.0.0.0 {-# INLINE invMod #-}-invMod :: (HasCallStack) => Int -> Int -> Int+invMod ::+ (HasCallStack) =>+ -- | \(x\)+ Int ->+ -- | \(m\)+ Int ->+ -- | \(x^{-1} \bmod m\)+ Int invMod x m = let !_ = ACIA.runtimeAssert (1 <= m) $ "AtCoder.Math.invMod: given invalid `m` less than 1: " ++ show m (!z1, !z2) = ACIM.invGcd (fromIntegral x) (fromIntegral m)@@ -66,7 +74,7 @@ -- ==== Complexity -- - \(O(n \log{\mathrm{lcm}(m[i])})\) ----- ==== Example+-- ==== __Example__ -- `crt` calculates \(y\) such that \(y \equiv r_i \pmod m_i, \forall i \in \lbrace 0,1,\cdots, n - 1 \rbrace\): -- -- >>> import Data.Vector.Unboxed qualified as VU@@ -127,7 +135,7 @@ -- ==== Complexity -- - \(O(\log m)\) ----- ==== Example+-- ==== __Example__ -- `floorSum` calculates the number of points surrounded by a line -- \(y = \frac {a \times x + b} {m} \) and \(x, y\) axes in \(O(\log m)\) time: --@@ -150,7 +158,18 @@ -- -- @since 1.0.0.0 {-# INLINE floorSum #-}-floorSum :: (HasCallStack) => Int -> Int -> Int -> Int -> Int+floorSum ::+ (HasCallStack) =>+ -- | \(n\)+ Int ->+ -- | \(m\)+ Int ->+ -- | \(a\)+ Int ->+ -- | \(b\)+ Int ->+ -- | \(\sum\limits_{i = 0}^{n - 1} \left\lfloor \frac{a \times i + b}{m} \right\rfloor\)+ Int floorSum n m a b = ACIM.floorSumUnsigned n m a' b' - da - db where !_ = ACIA.runtimeAssert (0 <= n && n < bit 32) $ "AtCoder.Math.floorSum: given invalid `n` (`" ++ show n ++ "`)"
src/AtCoder/MaxFlow.hs view
@@ -21,7 +21,7 @@ -- 1 -- -- Get the minimum cut with `minCut`. In this case, removing the second edge makes the minimum cut--- (note that the edge capacity (\(1\)) = max flow):+-- (note that the edge capacity \(1\) = max flow): -- -- >>> MF.minCut g 0 -- returns a Bit vector. `1` (`Bit True`) is on the `s` side. -- [1,1,0]@@ -116,7 +116,18 @@ -- -- @since 1.0.0.0 {-# INLINE addEdge #-}-addEdge :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> Int -> cap -> m Int+addEdge ::+ (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | from+ Int ->+ -- | to+ Int ->+ -- | cap+ cap ->+ -- | Edge index+ m Int addEdge MfGraph {..} from to cap = do let !_ = ACIA.checkCustom "AtCoder.MaxFlow.addEdge" "`from` vertex" from "the number of vertices" nG let !_ = ACIA.checkCustom "AtCoder.MaxFlow.addEdge" "`to` vertex" to "the number of vertices" nG@@ -131,7 +142,7 @@ ACIGV.pushBack (gG VG.! to) (from, iEdge, 0) pure m --- | `addEdge` with return value discarded.+-- | `addEdge` with the return value discarded. -- -- ==== Constraints -- - \(0 \leq \mathrm{from}, \mathrm{to} \lt n\)@@ -142,7 +153,17 @@ -- -- @since 1.0.0.0 {-# INLINE addEdge_ #-}-addEdge_ :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> Int -> cap -> m ()+addEdge_ ::+ (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | from+ Int ->+ -- | to+ Int ->+ -- | cap+ cap ->+ m () addEdge_ graph from to cap = do _ <- addEdge graph from to cap pure ()@@ -161,11 +182,22 @@ -- -- @since 1.0.0.0 {-# INLINE flow #-}-flow :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> Int -> cap -> m cap+flow ::+ (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | Source @s@+ Int ->+ -- | Sink @t@+ Int ->+ -- | Flow limit+ cap ->+ -- | Max flow+ m cap flow MfGraph {..} s t flowLimit = do let !_ = ACIA.checkCustom "AtCoder.MaxFlow.flow" "`source` vertex" s "the number of vertices" nG let !_ = ACIA.checkCustom "AtCoder.MaxFlow.flow" "`sink` vertex" t "the number of vertices" nG- let !_ = ACIA.runtimeAssert (s /= t) $ "AtCoder.MaxFlow.flow: `source` and `sink` vertex have to be distinct: `" ++ show s ++ "`"+ let !_ = ACIA.runtimeAssert (s /= t) $ "AtCoder.MaxFlow.flow: `source` and `sink` vertex must be distinct: `" ++ show s ++ "`" level <- VUM.unsafeNew nG que <- ACIQ.new nG@@ -253,7 +285,16 @@ -- -- @since 1.0.0.0 {-# INLINE maxFlow #-}-maxFlow :: (HasCallStack, PrimMonad m, Num cap, Ord cap, Bounded cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> Int -> m cap+maxFlow ::+ (HasCallStack, PrimMonad m, Num cap, Ord cap, Bounded cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | Source @s@+ Int ->+ -- | Sink @t@+ Int ->+ -- | Max flow+ m cap maxFlow graph s t = flow graph s t maxBound -- | Returns a vector of length \(n\), such that the \(i\)-th element is `True` if and only if there@@ -265,7 +306,14 @@ -- -- @since 1.0.0.0 {-# INLINE minCut #-}-minCut :: (PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> m (VU.Vector Bit)+minCut ::+ (PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | Source @s@+ Int ->+ -- | Minimum cut+ m (VU.Vector Bit) minCut MfGraph {..} s = do visited <- VUM.replicate nG $ Bit False que <- ACIQ.new nG -- we could use a growable queue here@@ -296,7 +344,14 @@ -- -- @since 1.0.0.0 {-# INLINE getEdge #-}-getEdge :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> m (Int, Int, cap, cap)+getEdge ::+ (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | Vertex+ Int ->+ -- | Tuple of @(from, to, cap, flow)@+ m (Int, Int, cap, cap) getEdge MfGraph {..} i = do m <- ACIGV.length posG let !_ = ACIA.checkEdge "AtCoder.MaxFlow.getEdge" i m@@ -313,13 +368,18 @@ -- -- @since 1.0.0.0 {-# INLINE edges #-}-edges :: (PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> m (VU.Vector (Int, Int, cap, cap))+edges ::+ (PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | Vector of @(from, to, cap, flow)@+ m (VU.Vector (Int, Int, cap, cap)) edges g@MfGraph {posG} = do len <- ACIGV.length posG VU.generateM len (getEdge g) -- | \(O(1)\) Changes the capacity and the flow amount of the $i$-th edge to @newCap@ and--- @newFlow@, respectively. It doesn't change the capacity or the flow amount of other edges.+-- @newFlow@, respectively. It oes not change the capacity or the flow amount of other edges. -- -- ==== Constraints -- - \(0 \leq \mathrm{newflow} \leq \mathrm{newcap}\)@@ -329,7 +389,17 @@ -- -- @since 1.0.0.0 {-# INLINE changeEdge #-}-changeEdge :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) => MfGraph (PrimState m) cap -> Int -> cap -> cap -> m ()+changeEdge ::+ (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap) =>+ -- | Graph+ MfGraph (PrimState m) cap ->+ -- | Edge index+ Int ->+ -- | New capacity+ cap ->+ -- | New flow+ cap ->+ m () changeEdge MfGraph {..} i newCap newFlow = do m <- ACIGV.length posG let !_ = ACIA.checkEdge "AtCoder.MaxFlow.changeEdge" i m
src/AtCoder/MinCostFlow.hs view
@@ -110,11 +110,17 @@ {-# INLINE addEdge #-} addEdge :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | from Int ->+ -- | to Int ->+ -- | capacity cap ->+ -- | cost cost ->+ -- | Edge index m Int addEdge McfGraph {..} from to cap cost = do let !_ = ACIA.checkCustom "AtCoder.MinCostFlow.addEdge" "`from` vertex" from "the number of vertices" nG@@ -125,7 +131,7 @@ ACIGV.pushBack edgesG (from, to, cap, 0, cost) pure m --- | `addEdge` with return value discarded.+-- | `addEdge` with the return value discarded. -- -- ==== Constraints -- - \(0 \leq \mathrm{from}, \mathrm{to} \lt n\)@@ -138,10 +144,15 @@ {-# INLINE addEdge_ #-} addEdge_ :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | from Int ->+ -- | to Int ->+ -- | capacity cap ->+ -- | cost cost -> m () addEdge_ graph from to cap cost = do@@ -161,10 +172,15 @@ {-# INLINE flow #-} flow :: (HasCallStack, PrimMonad m, Integral cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, Bounded cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | Fource @s@ Int ->+ -- | Sink @t@ Int ->+ -- | Flow limit cap ->+ -- | Tuple of @(cap, cost@) m (cap, cost) flow graph s t flowLimit = do res <- slope graph s t flowLimit@@ -182,9 +198,13 @@ {-# INLINE maxFlow #-} maxFlow :: (HasCallStack, PrimMonad m, Integral cap, Ord cap, Bounded cap, VU.Unbox cap, Num cost, Ord cost, Bounded cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | Source @s@ Int ->+ -- | Sink @t@ Int ->+ -- | Tuple of @(cap, cost@) m (cap, cost) maxFlow graph s t = do res <- slope graph s t maxBound@@ -216,15 +236,20 @@ {-# INLINE slope #-} slope :: (HasCallStack, PrimMonad m, Integral cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, Bounded cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | Source @s@ Int ->+ -- | Sink @t@ Int ->+ -- | Flow limit cap ->+ -- | Vector of @(cap, cost)@ m (VU.Vector (cap, cost)) slope McfGraph {..} s t flowLimit = do let !_ = ACIA.checkCustom "AtCoder.MinCostFlow.slope" "`source` vertex" s "the number of vertices" nG let !_ = ACIA.checkCustom "AtCoder.MinCostFlow.slope" "`sink` vertex" t "the number of vertices" nG- let !_ = ACIA.runtimeAssert (s /= t) "AtCoder.MinCostFlow.slope: `source` and `sink` vertex have to be distict"+ let !_ = ACIA.runtimeAssert (s /= t) "AtCoder.MinCostFlow.slope: `source` and `sink` vertex must be distict" edges_@(VU.V_5 _ _ _ caps _ _) <- ACIGV.unsafeFreeze edgesG (!edgeIdx, !g) <- ACIMCSR.build nG edges_@@ -292,8 +317,8 @@ cap <- VGM.read capCsr $ start + di unless (cap == 0) $ do- -- \|-dual[e.to] + dual[v]| <= (n-1)C- -- cost <= C - -(n-1)C + 0 = nC+ -- - |-dual[e.to] + dual[v]| <= (n-1)C+ -- - cost <= C - -(n-1)C + 0 = nC cost' <- do dualTo <- VGM.read duals to pure $! cost - dualTo + dualV@@ -368,8 +393,11 @@ {-# INLINE getEdge #-} getEdge :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | Edge index Int ->+ -- | Tuple of @(from, to, cap, flow, cost)@ m (Int, Int, cap, cap, cost) getEdge McfGraph {..} i = do m <- ACIGV.length edgesG@@ -386,7 +414,9 @@ {-# INLINE edges #-} edges :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | Vector of @(from, to, cap, flow, cost)@ m (VU.Vector (Int, Int, cap, cap, cost)) edges McfGraph {..} = do ACIGV.freeze edgesG@@ -401,7 +431,9 @@ {-# INLINE unsafeEdges #-} unsafeEdges :: (HasCallStack, PrimMonad m, Num cap, Ord cap, VU.Unbox cap, Num cost, Ord cost, VU.Unbox cost) =>+ -- | Graph McfGraph (PrimState m) cap cost ->+ -- | Vector of @(from, to, cap, flow, cost)@ m (VU.Vector (Int, Int, cap, cap, cost)) unsafeEdges McfGraph {..} = do ACIGV.unsafeFreeze edgesG
src/AtCoder/ModInt.hs view
@@ -1,11 +1,11 @@ {-# LANGUAGE MagicHash #-} {-# LANGUAGE TypeFamilies #-} --- | It is the struct that treats the modular arithmetic. All the remaining parts of AC Library+-- | It is the structure that treats the modular arithmetic. All the remaining parts of AC Library -- works without modint, so you don't necessarily read this to use the remaining parts. ----- For most of the problems, it is sufficient to use `ModInt998244353`, `ModInt1000000007`, which--- can be used as follows.+-- ==== __Example__+-- It is often convenient to define a type alias of `ModInt` for a specific modulus value: -- -- >>> import AtCoder.ModInt qualified as M -- >>> type Mint = M.ModInt998244353@@ -13,7 +13,11 @@ -- >>> modInt 1000000000 -- 1755647 --+-- >>> modInt 1000000000 / modInt 3+-- 666081451+-- -- ==== Major changes from the original @ac-library@+-- - @StaticModInt@ is renamed to `ModInt`. -- - @DynamicModInt@ is removed. -- -- @since 1.0.0.0@@ -82,14 +86,14 @@ -- @since 1.0.0.0 isPrimeModulus :: Proxy# a -> Bool - -- | Returns the primitive root of the modulus value. Note that the default implementation is- -- slow.+ -- | Returns the primitive root of the modulus value. Note that the default implementation is slow+ -- and the value should be hard-coded. -- -- @since 1.0.0.0 {-# INLINE primitiveRootModulus #-} primitiveRootModulus :: Proxy# a -> Int -- we could use `AllowAmbigousTypes` or `Tagged` newtype, but `Proxy#` wasn't so slow.- -- not sure about `x^n` case though..+ -- not sure about the case of `x^n` though.. primitiveRootModulus _ = ACIM.primitiveRoot $ fromIntegral (natVal' (proxy# @a)) -- | \(2^{24} - 1\).@@ -119,7 +123,7 @@ {-# INLINE primitiveRootModulus #-} primitiveRootModulus _ = 11 --- | \(119 \times 2^{23} + 1\). It is often used in contest problems+-- | \(119 \times 2^{23} + 1\). It is often used in contest problems. -- -- @since 1.0.0.0 instance Modulus 998244353 where@@ -146,17 +150,13 @@ {-# INLINE primitiveRootModulus #-} primitiveRootModulus _ = 7 --- | `ModInt` with modulus value @998244353@.------ @since 1.0.0.0+-- | @since 1.0.0.0 type ModInt998244353 = ModInt 998244353 --- | `ModInt` with modulus value @1000000007@.------ @since 1.0.0.0+-- | @since 1.0.0.0 type ModInt1000000007 = ModInt 1000000007 --- | Retrieves `Int` from `KnownNat`.+-- | Retrieves the `Int` value from a `KnownNat`. -- -- >>> import Data.Proxy (Proxy(..)) -- >>> modVal (Proxy @42)@@ -167,7 +167,7 @@ modVal :: forall a. (KnownNat a) => Proxy a -> Int modVal p = fromIntegral $ natVal p --- | Retrieves `Int` from `KnownNat`.+-- | Retrieves the `Int` value from a `KnownNat`. -- -- >>> :set -XMagicHash -- >>> import GHC.Exts (proxy#)@@ -179,28 +179,28 @@ modVal# :: forall a. (KnownNat a) => Proxy# a -> Int modVal# p = fromIntegral $ natVal' p --- | Creates `ModInt` from an `Int` value taking mod.+-- | Creates a `ModInt` from an `Int` value taking the mod. -- -- @since 1.0.0.0 {-# INLINE new #-} new :: forall a. (KnownNat a) => Int -> ModInt a new v = ModInt . fromIntegral $ v `mod` fromIntegral (natVal' (proxy# @a)) --- | Creates `ModInt` from a `Word32` value taking mod.+-- | Creates a `ModInt` from a `Word32` value taking the mod. -- -- @since 1.0.0.0 {-# INLINE new32 #-} new32 :: forall a. (KnownNat a) => Word32 -> ModInt a new32 v = ModInt $ v `mod` fromIntegral (natVal' (proxy# @a)) --- | Creates `ModInt` from a `Word64` value taking mod.+-- | Creates a `ModInt` from a `Word64` value taking the mod. -- -- @since 1.0.0.0 {-# INLINE new64 #-} new64 :: forall a. (KnownNat a) => Word64 -> ModInt a new64 v = ModInt . fromIntegral $ v `mod` fromIntegral (natVal' (proxy# @a)) --- | Creates `ModInt` without taking mod. It is the function for constant-factor speedup.+-- | Creates `ModInt` without taking the mod. It is the function for constant-factor speedup. -- -- ==== Constraints -- - \(0 \leq x \lt \mathrm{mod}\) (not asserted at runtime)@@ -210,20 +210,23 @@ unsafeNew :: (KnownNat a) => Word32 -> ModInt a unsafeNew = ModInt --- | `Word32` value that treats the modula arithmetic.-newtype ModInt a = ModInt {unModInt :: Word32}+-- | `Word32` value that treats the modular arithmetic.+newtype ModInt a = ModInt+ { -- | @since 1.0.0.0+ unModInt :: Word32+ } deriving- ( -- @since 1.0.0.0+ ( -- | @since 1.0.0.0 P.Prim ) deriving newtype- ( -- @since 1.0.0.0+ ( -- | @since 1.0.0.0 Eq,- -- @since 1.0.0.0+ -- | @since 1.0.0.0 Ord,- -- @since 1.0.0.0+ -- | @since 1.0.0.0 Read,- -- @since 1.0.0.0+ -- | @since 1.0.0.0 Show ) @@ -322,10 +325,10 @@ !_ = ACIA.runtimeAssert (eg1 == 1) "AtCoder.ModInt.inv: `x^(-1) mod m` cannot be calculated when `gcd x modulus /= 1`" in fromIntegral eg2 --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 deriving newtype instance (KnownNat p) => Real (ModInt p) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 instance (KnownNat p) => Num (ModInt p) where {-# INLINE (+) #-} (ModInt !x1) + (ModInt !x2)@@ -355,45 +358,45 @@ {-# INLINE fromInteger #-} fromInteger = ModInt . fromInteger . (`mod` fromIntegral (natVal' (proxy# @p))) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 instance (KnownNat p) => Bounded (ModInt p) where {-# INLINE minBound #-} minBound = ModInt 0 {-# INLINE maxBound #-} maxBound = ModInt $! fromIntegral (natVal' (proxy# @p)) - 1 --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 instance (KnownNat p) => Enum (ModInt p) where {-# INLINE toEnum #-} toEnum = new {-# INLINE fromEnum #-} fromEnum = fromIntegral . unModInt --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 instance (Modulus p) => Integral (ModInt p) where {-# INLINE quotRem #-} quotRem x y = (x / y, x - x / y * y) {-# INLINE toInteger #-} toInteger = coerce (toInteger @Word32) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 instance (Modulus p) => Fractional (ModInt p) where {-# INLINE recip #-} recip = inv {-# INLINE fromRational #-} fromRational q = fromInteger (numerator q) / fromInteger (denominator q) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 newtype instance VU.MVector s (ModInt a) = MV_ModInt (VU.MVector s Word32) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 newtype instance VU.Vector (ModInt a) = V_ModInt (VU.Vector Word32) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 deriving newtype instance VGM.MVector VU.MVector (ModInt a) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 deriving newtype instance VG.Vector VU.Vector (ModInt a) --- | -- @since 1.0.0.0+-- | @since 1.0.0.0 instance VU.Unbox (ModInt a)
src/AtCoder/Scc.hs view
@@ -1,16 +1,22 @@ -- | It calculates the strongly connected components of directed graphs. ----- ==== Example+-- ==== __Example__+-- Create a `SccGraph`:+-- -- >>> import AtCoder.Scc qualified as Scc -- >>> gr <- Scc.new 4 -- 0 1 2 3 -- >>> Scc.nScc gr -- 4 --+-- Add edges and get SCC of the graph:+-- -- >>> Scc.addEdge gr 0 1 -- 0 -> 1 2 3 -- >>> Scc.addEdge gr 1 0 -- 0 == 1 2 3 -- >>> Scc.addEdge gr 1 2 -- 0 == 1 -> 2 3 -- >>> Scc.scc gr -- [[3],[0,1],[2]]+--+-- See also the @scc@ function in @AtCoder.Extra.Graph@ module that computes SCC for a CSR. -- -- @since 1.0.0.0 module AtCoder.Scc (SccGraph, nScc, new, addEdge, scc) where
src/AtCoder/SegTree.hs view
@@ -21,6 +21,7 @@ -- Create a `SegTree` of @'Sum' Int@: -- -- >>> import AtCoder.SegTree qualified as ST+-- >>> import Data.Vector.Unboxed qualified as VU -- >>> import Data.Monoid (Sum(..)) -- >>> seg <- ST.new @_ @(Sum Int) 4 --@@ -57,13 +58,13 @@ -- -- - `prod` returns \(a_l \cdot a_{l + 1} \cdot .. \cdot a_{r - 1}\). If you need \(a_{r - 1} \cdot a_{r - 2} \cdot .. \cdot a_{l}\), -- wrap your monoid in `Data.Monoid.Dual`.--- - If you ever need to store boxed types to `LazySegTree`, wrap it in 'vector:Data.Vector.Unboxed.DoNotUnboxStrict'+-- - If you ever need to store boxed types to `LazySegTree`, wrap it in @Data.Vector.Unboxed.DoNotUnboxStrict@ -- or the like. -- -- ==== Major changes from the original @ac-library@--- - The implementation is `Monoid` based.+-- - The implementation is `Monoid` based, not function objects. -- - @get@ and @set@ are renamed to `read` and `write`.--- - `modify`, `modifyM`, `freeze` and `unsafeFreeze` are added.+-- - `modify`, `modifyM`, `exchange`, `freeze` and `unsafeFreeze` are added. -- -- @since 1.0.0.0 module AtCoder.SegTree@@ -74,10 +75,11 @@ new, build, - -- * Accessing individual elements+ -- * Accessing elements write, modify, modifyM,+ exchange, read, -- * Products@@ -145,7 +147,7 @@ new :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => Int -> m (SegTree (PrimState m) a) new nSt | nSt >= 0 = build $ VU.replicate nSt mempty- | otherwise = error $ "new: given negative size (`" ++ show nSt ++ "`)"+ | otherwise = error $ "AtCoder.SegTree.new: given negative size (`" ++ show nSt ++ "`)" -- | Creates an array with initial values. --@@ -218,6 +220,25 @@ for_ [1 .. logSt] $ \i -> do update self ((p + sizeSt) .>>. i) +-- | (Extra API) Writes \(p\)-th value of the array to \(x\) and returns the old value.+--+-- ==== Constraints+-- - \(0 \leq p \lt n\)+--+-- ==== Complexity+-- - \(O(\log n)\)+--+-- @since 1.1.0.0+{-# INLINE exchange #-}+exchange :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => SegTree (PrimState m) a -> Int -> a -> m a+exchange self@SegTree {..} p x = do+ let !_ = ACIA.checkIndex "AtCoder.SegTree.exchange" p nSt+ ret <- VGM.exchange dSt (p + sizeSt) x+ VGM.write dSt (p + sizeSt) x+ for_ [1 .. logSt] $ \i -> do+ update self ((p + sizeSt) .>>. i)+ pure ret+ -- | Returns \(p\)-th value of the array. -- -- ==== Constraints@@ -249,8 +270,8 @@ | ACIA.testInterval l0 r0 nSt = unsafeProd self l0 r0 | otherwise = ACIA.errorInterval "AtCoder.SegTree.prod" l0 r0 nSt --- | Total version of `prod`. Returns \(a[l] \cdot ... \cdot a[r - 1]\), assuming the properties of--- the monoid. It returns `Just` `mempty` if \(l = r\). It return `Nothing` if the interval is+-- | Total variant of `prod`. Returns \(a[l] \cdot ... \cdot a[r - 1]\), assuming the properties of+-- the monoid. It returns `Just` `mempty` if \(l = r\). Returns `Nothing` if the interval is -- invalid. -- -- ==== Complexity@@ -315,10 +336,19 @@ -- -- @since 1.0.0.0 {-# INLINE minLeft #-}-minLeft :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => SegTree (PrimState m) a -> Int -> (a -> Bool) -> m Int+minLeft ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | The segment tree+ SegTree (PrimState m) a ->+ -- | \(r\)+ Int ->+ -- | \(p\): user prediate+ (a -> Bool) ->+ -- | \(l\): \(p\) holds for \([l, r)\)+ m Int minLeft seg r0 f = minLeftM seg r0 (pure . f) --- | Monadic version of `minLeft`.+-- | Monadic variant of `minLeft`. -- -- ==== Constraints --@@ -332,7 +362,16 @@ -- -- @since 1.0.0.0 {-# INLINE minLeftM #-}-minLeftM :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => SegTree (PrimState m) a -> Int -> (a -> m Bool) -> m Int+minLeftM ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | The segment tree+ SegTree (PrimState m) a ->+ -- | \(r\)+ Int ->+ -- | \(p\): user prediate+ (a -> m Bool) ->+ -- | \(l\): \(p\) holds for \([l, r)\)+ m Int minLeftM SegTree {..} r0 f = do b <- f mempty let !_ = ACIA.runtimeAssert b "AtCoder.SegTree.minLeftM: `f empty` returned `False`"@@ -385,10 +424,19 @@ -- -- @since 1.0.0.0 {-# INLINE maxRight #-}-maxRight :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => SegTree (PrimState m) a -> Int -> (a -> Bool) -> m Int+maxRight ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | The segment tree+ SegTree (PrimState m) a ->+ -- | \(l\)+ Int ->+ -- | \(p\): user prediate+ (a -> Bool) ->+ -- | \(r\): \(p\) holds for \([l, r)\)+ m Int maxRight seg l0 f = maxRightM seg l0 (pure . f) --- | Moandic version of `maxRight`.+-- | Moandic variant of `maxRight`. -- -- ==== Constraints -- - if \(f\) is called with the same argument, it returns the same value, i.e., \(f\) has no side effect.@@ -400,7 +448,16 @@ -- -- @since 1.0.0.0 {-# INLINE maxRightM #-}-maxRightM :: (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) => SegTree (PrimState m) a -> Int -> (a -> m Bool) -> m Int+maxRightM ::+ (HasCallStack, PrimMonad m, Monoid a, VU.Unbox a) =>+ -- | The segment tree+ SegTree (PrimState m) a ->+ -- | \(l\)+ Int ->+ -- | \(p\): user prediate+ (a -> m Bool) ->+ -- | \(r\): \(p\) holds for \([l, r)\)+ m Int maxRightM SegTree {..} l0 f = do b <- f mempty let !_ = ACIA.runtimeAssert b "AtCoder.SegTree.maxRightM: `f mempty` returned `False`"
src/AtCoder/String.hs view
@@ -1,9 +1,9 @@ -- | It contains string algorithms. ----- Let @s@ be a string. We denote the substring of @s@ between \(a\)-th and \(b - 1\)-th character--- by @s[a..b)@.+-- Let \(s\) be a string. We denote the substring of \(s\) between \(a\)-th and \(b - 1\)-th+-- character by \(s[a..b)\). ----- ==== Examples+-- ==== __Examples__ -- -- ===== Suffix Array and LCP Array --@@ -32,9 +32,9 @@ -- * LCP array lcpArray, lcpArrayBS,- zAlgorithm, -- * Z algorithm+ zAlgorithm, zAlgorithmBS, ) where@@ -55,9 +55,9 @@ -- | Calculates suffix array for a `Int` vector. ----- Given a string @s@ of length \(n\), it returns the suffix array of @s@. Here, the suffix array--- @sa@ of @s@ is a permutation of \(0, \cdots, n-1\) such that @s[sa[i]..n) < s[sa[i+1]..n)@ holds--- for all \(i = 0,1, \cdots ,n-2\).+-- Given a string \(s\) of length \(n\), it returns the suffix array of \(s\). Here, the suffix array+-- \(\mathrm{sa}\) of \(s\) is a permutation of \(0, \cdots, n-1\) such that \(s[\mathrm{sa}[i]..n) < s[\mathrm{sa}[i+1]..n)\)+-- holds for all \(i = 0,1, \cdots ,n-2\). -- -- ==== Constraints -- - \(0 \leq n\)@@ -65,7 +65,7 @@ -- - \(0 \leq x \leq \mathrm{upper}\) for all elements \(x\) of \(s\). -- -- ==== Complexity--- - (3) \(O(n + \mathrm{upper})\)-time+-- - \(O(n + \mathrm{upper})\)-time -- -- @since 1.0.0.0 {-# INLINE suffixArray #-}@@ -81,7 +81,7 @@ -- - \(0 \leq n\) -- -- ==== Complexity--- - (1) \(O(n)\)-time+-- - \(O(n)\)-time -- -- @since 1.0.0.0 {-# INLINE suffixArrayBS #-}@@ -97,7 +97,8 @@ -- - \(0 \leq n\) -- -- ==== Complexity--- - (2) \(O(n \log n)\)-time, \(O(n)\)-space+-- - \(O(n \log n)\)-time+-- - \(O(n)\)-space -- -- @since 1.0.0.0 {-# INLINE suffixArrayOrd #-}@@ -124,12 +125,12 @@ (upper_,) <$> VU.unsafeFreeze vec in ACIS.saIs s2 upper --- | Given a string @s@ of length \(n\), it returns the LCP array of @s@. Here, the LCP array of--- @s@ is the array of length \(n-1\), such that the \(i\)-th element is the length of the LCP--- (Longest Common Prefix) of @s[sa[i]..n)@ and @s[sa[i+1]..n)@+-- | Given a string \(s\) of length \(n\), it returns the LCP array of \(s\). Here, the LCP array of+-- \(s\) is the array of length \(n-1\), such that the \(i\)-th element is the length of the LCP+-- (Longest Common Prefix) of \(s[\mathrm{sa}[i]..n)\) and \(s[\mathrm{sa}[i+1]..n)\). -- -- ==== Constraints--- - The second argument is the suffix array of @s@.+-- - The second argument is the suffix array of \(s\). -- - \(1 \leq n\) -- -- ==== Complexity@@ -137,7 +138,14 @@ -- -- @since 1.0.0.0 {-# INLINE lcpArray #-}-lcpArray :: (HasCallStack, Ord a, VU.Unbox a) => VU.Vector a -> VU.Vector Int -> VU.Vector Int+lcpArray ::+ (HasCallStack, Ord a, VU.Unbox a) =>+ -- | A vector representing a string+ VU.Vector a ->+ -- | Suffix array+ VU.Vector Int ->+ -- | LCP array+ VU.Vector Int lcpArray s sa = let n = VU.length s !_ = ACIA.runtimeAssert (n >= 1) "AtCoder.String.lcpArray: given empty input"@@ -167,10 +175,10 @@ rnk pure lcp --- | @ByteString@ verison of `lcpArray`.+-- | @ByteString@ variant of `lcpArray`. -- -- ==== Constraints--- - The second argument is the suffix array of @s@.+-- - The second argument is the suffix array of \(s\). -- - \(1 \leq n\) -- -- ==== Complexity@@ -178,17 +186,25 @@ -- -- @since 1.0.0.0 {-# INLINE lcpArrayBS #-}-lcpArrayBS :: (HasCallStack) => BS.ByteString -> VU.Vector Int -> VU.Vector Int+lcpArrayBS ::+ (HasCallStack) =>+ -- | String+ BS.ByteString ->+ -- | Suffix array+ VU.Vector Int ->+ -- | LCP array+ VU.Vector Int lcpArrayBS s sa = let n = BS.length s s2 = VU.map ord . VU.fromListN n $ BS.unpack s in lcpArray s2 sa -- | Given a `Ord` vector of length \(n\), it returns the array of length \(n\), such that the--- \(i\)-th element is the length of the LCP (Longest Common Prefix) of @s[0..n)@ and @s[i..n)@.+-- \(i\)-th element is the length of the LCP (Longest Common Prefix) of \(s[0..n)\) and \(s[i..n)\). -- -- ==== Constraints -- - \(n \leq n\)+-- -- ==== Complexity -- - \(O(n)\) --@@ -227,10 +243,11 @@ n = VU.length s -- | Given a string of length \(n\), it returns the array of length \(n\), such that the \(i\)-th--- element is the length of the LCP (Longest Common Prefix) of @s[0..n)@ and @s[i..n)@.+-- element is the length of the LCP (Longest Common Prefix) of \(s[0..n)\) and \(s[i..n)\). -- -- ==== Constraints -- - \(n \leq n\)+-- -- ==== Complexity -- - \(O(n)\) --
src/AtCoder/TwoSat.hs view
@@ -8,7 +8,7 @@ -- -- it decides whether there is a truth assignment that satisfies all clauses. ----- ==== Example+-- ==== __Example__ -- >>> import AtCoder.TwoSat qualified as TS -- >>> import Data.Bit (Bit(..)) -- >>> ts <- TS.new 1
test/Main.hs view
@@ -4,8 +4,20 @@ import Test.Tasty.Ingredients.Rerun import Tests.Convolution qualified import Tests.Dsu qualified+import Tests.Extra.Bisect qualified+import Tests.Extra.HashMap qualified+import Tests.Extra.IntMap qualified+import Tests.Extra.IntSet qualified+import Tests.Extra.IntervalMap qualified import Tests.Extra.Math qualified import Tests.Extra.Monoid qualified+import Tests.Extra.MultiSet qualified+import Tests.Extra.Semigroup.Matrix qualified+import Tests.Extra.Semigroup.Permutation qualified+import Tests.Extra.WaveletMatrix qualified+import Tests.Extra.WaveletMatrix.BitVector qualified+import Tests.Extra.WaveletMatrix.Raw qualified+import Tests.Extra.WaveletMatrix2d qualified import Tests.FenwickTree qualified import Tests.Internal.Bit qualified import Tests.Internal.Buffer qualified@@ -31,8 +43,23 @@ . testGroup "toplevel" $ [ testGroup "Convolution" Tests.Convolution.tests, testGroup "Dsu" Tests.Dsu.tests,- testGroup "Extra.Math" Tests.Extra.Math.tests,- testGroup "Extra.Monoid" Tests.Extra.Monoid.tests,+ testGroup+ "Extra"+ [ testGroup "Bisect" Tests.Extra.Bisect.tests,+ testGroup "HashMap" Tests.Extra.HashMap.tests,+ testGroup "IntervalMap" Tests.Extra.IntervalMap.tests,+ testGroup "IntMap" Tests.Extra.IntMap.tests,+ testGroup "IntSet" Tests.Extra.IntSet.tests,+ testGroup "Math" Tests.Extra.Math.tests,+ testGroup "Monoid" Tests.Extra.Monoid.tests,+ testGroup "MultiSet" Tests.Extra.MultiSet.tests,+ testGroup "Semigroup.Matrix" Tests.Extra.Semigroup.Matrix.tests,+ testGroup "Semigroup.Permutation" Tests.Extra.Semigroup.Permutation.tests,+ testGroup "WaveletMatrix" Tests.Extra.WaveletMatrix.tests,+ testGroup "WaveletMatrix.BitVector" Tests.Extra.WaveletMatrix.BitVector.tests,+ testGroup "WaveletMatrix.Raw" Tests.Extra.WaveletMatrix.Raw.tests,+ testGroup "WaveletMatrix2d" Tests.Extra.WaveletMatrix2d.tests+ ], testGroup "FenwickTree" Tests.FenwickTree.tests, testGroup "Internal"
+ test/Tests/Extra/Bisect.hs view
@@ -0,0 +1,114 @@+module Tests.Extra.Bisect where++import AtCoder.Extra.Bisect+import Data.List qualified as L+import Data.Vector.Generic qualified as VG+import Data.Vector.Unboxed qualified as VU+import Test.Tasty+import Test.Tasty.QuickCheck as QC++-- | Takes half-open interval [l, r).+naivePartition :: Int -> Int -> (Int -> Bool) -> VU.Vector Int -> (Maybe Int, Maybe Int)+naivePartition l r p xs+ | l >= r = (Nothing, Nothing)+ | otherwise = case (VU.null ls, VU.null rs) of+ (True, True) -> error "unreachable"+ (False, True) -> (Just l', Nothing)+ (True, False) -> (Nothing, Just r')+ _ -> (Just l', Just r')+ where+ xs' = VU.take (r - l) . VU.drop l $ xs+ (!ls, !rs) = VU.partition p xs'+ l' = l + VU.length ls - 1+ r' = l' + 1++naiveLowerBound :: VU.Vector Int -> Int -> Maybe Int+naiveLowerBound xs = naiveLowerBoundIn 0 (VU.length xs) xs++naiveLowerBoundIn :: Int -> Int -> VU.Vector Int -> Int -> Maybe Int+naiveLowerBoundIn l r xs target = case naivePartition l r (< target) xs of+ (!_, Just i) -> Just i+ _ -> Nothing++naiveUpperBound :: VU.Vector Int -> Int -> Maybe Int+naiveUpperBound xs = naiveUpperBoundIn 0 (VU.length xs) xs++naiveUpperBoundIn :: Int -> Int -> VU.Vector Int -> Int -> Maybe Int+naiveUpperBoundIn l r xs target = case naivePartition l r (<= target) xs of+ (!_, Just i) -> Just i+ _ -> Nothing++boundsQueryGen :: Gen (Int, Int, VU.Vector Int)+boundsQueryGen = do+ n <- QC.chooseInt (1, 100)+ p <- QC.chooseInt (-25, 25)+ xs <- VU.fromList . L.sort <$> QC.vectorOf n (QC.chooseInt (-20, 20))+ pure (n, p, xs)++bisectQueryGen :: Gen (Int, Int, VU.Vector Int, [(Int, Int)])+bisectQueryGen = do+ n <- QC.chooseInt (1, 100)+ p <- QC.chooseInt (-25, 25)+ xs <- VU.fromList . L.sort <$> QC.vectorOf n (QC.chooseInt (-20, 20))+ let lrs = [(l, r) | l <- [0 .. n], r <- [l .. n]]+ pure (n, p, xs, lrs)++prop_lowerBound :: TestTree+prop_lowerBound = QC.testProperty "lowerBound" $ do+ (!_, !target, !xs) <- boundsQueryGen+ pure $ naiveLowerBound xs target QC.=== lowerBound xs target++prop_lowerBoundIn :: TestTree+prop_lowerBoundIn = QC.testProperty "lowerBoundIn" $ do+ (!_, !target, !xs, !lrs) <- bisectQueryGen+ pure . QC.conjoin $+ map+ ( \(!l, !r) ->+ naiveLowerBoundIn l r xs target == lowerBoundIn l r xs target+ )+ lrs++prop_upperBound :: TestTree+prop_upperBound = QC.testProperty "upperBound" $ do+ (!_, !target, !xs) <- boundsQueryGen+ pure $ naiveUpperBound xs target QC.=== upperBound xs target++prop_upperBoundIn :: TestTree+prop_upperBoundIn = QC.testProperty "upperBoundIn" $ do+ (!_, !target, !xs, !lrs) <- bisectQueryGen+ pure . QC.conjoin $+ map+ ( \(!l, !r) ->+ naiveUpperBoundIn l r xs target == upperBoundIn l r xs target+ )+ lrs++prop_bisectL :: TestTree+prop_bisectL = QC.testProperty "bisectL" $ do+ (!_, !boundary, !xs, !lrs) <- bisectQueryGen+ pure . QC.conjoin $+ map+ ( \(!l, !r) ->+ fst (naivePartition l r (<= boundary) xs) == bisectL l r (\i -> xs VG.! i <= boundary)+ )+ lrs++prop_bisectR :: TestTree+prop_bisectR = QC.testProperty "bisectR" $ do+ (!_, !boundary, !xs, !lrs) <- bisectQueryGen+ pure . QC.conjoin $+ map+ ( \(!l, !r) ->+ snd (naivePartition l r (<= boundary) xs) == bisectR l r (\i -> xs VG.! i <= boundary)+ )+ lrs++tests :: [TestTree]+tests =+ [ prop_lowerBound,+ prop_upperBound,+ prop_lowerBoundIn,+ prop_upperBoundIn,+ prop_bisectL,+ prop_bisectR+ ]
+ test/Tests/Extra/Graph.hs view
@@ -0,0 +1,52 @@+module Tests.Extra.Graph where++import AtCoder.Extra.Graph qualified as Gr+import AtCoder.Internal.Buffer qualified as B+import Control.Monad (unless)+import Control.Monad.Fix (fix)+import Control.Monad.ST (runST)+import Data.List qualified as L+import Data.Vector.Generic qualified as VG+import Data.Vector.Unboxed qualified as VU+import Data.Vector.Unboxed.Mutable qualified as VUM+import Test.Tasty+import Test.Tasty.QuickCheck as QC++genDag :: Int -> QC.Gen (Gr.Csr ())+genDag n = do+ edges <- VU.fromList <$> QC.sublistOf [(u, v) | u <- [0 .. n - 1], v <- [u + 1 .. n - 1]]+ verts <- VU.fromList <$> QC.shuffle [0 .. n - 1]+ pure $ Gr.build n $ VU.map (\(!u, !v) -> (verts VG.! u, verts VG.! v, ())) edges++dfs :: Int -> (Int -> VU.Vector Int) -> Int -> VU.Vector Int+dfs n gr u0 = runST $ do+ buf <- B.new n+ vis <- VUM.replicate n False+ flip fix u0 $ \loop u -> do+ VU.forM_ (gr u) $ \v -> do+ b <- VUM.read vis v+ unless b $ do+ B.pushBack buf v+ loop v+ B.unsafeFreeze buf++testTopSort :: Int -> Gr.Csr () -> VU.Vector Int -> Bool+testTopSort n gr vs = and+ [ VU.notElem v (dfs n (gr `Gr.adj`) u)+ | u <- (vs VG.!) <$> [0 .. n - 1],+ v <- (vs VG.!) <$> [u + 1 .. n - 1]+ ]++-- | Tests lexicographically smallest topological ordering.+prop_topSort :: QC.Gen QC.Property+prop_topSort = do+ n <- QC.chooseInt (1, 8)+ dag <- genDag n+ let vs = Gr.topSort n (dag `Gr.adj`)+ let perms = map (VU.fromListN n) $ L.permutations [0 .. n - 1]+ pure $ vs QC.=== head (filter (testTopSort n dag) perms)++tests :: [TestTree]+tests =+ [ QC.testProperty "topSort" prop_topSort+ ]
+ test/Tests/Extra/HashMap.hs view
@@ -0,0 +1,171 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.HashMap where++import AtCoder.Extra.HashMap qualified as HM+import Control.Monad (foldM_)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (RealWorld)+import Data.HashMap.Strict qualified as HMR -- R: referencial implementation+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Unboxed qualified as VU+import System.IO.Unsafe (unsafePerformIO)+import Test.Hspec+import Test.QuickCheck.Monadic as QCM+import Test.Tasty+import Test.Tasty.Hspec+import Test.Tasty.QuickCheck as QC++spec_invalid :: IO TestTree+spec_invalid = testSpec "capacity limit" $ do+ it "throws error 1" $ do+ hm <- HM.new @_ @Int 1+ HM.insert hm 0 0+ HM.insert hm 0 1+ HM.insert hm 1 2 `shouldThrow` anyException++ it "throws error 2" $ do+ hm <- HM.new @_ @Int 2+ HM.insert hm 0 0+ HM.insert hm 1 1+ HM.insert hm 1 2+ HM.insert hm 2 2 `shouldThrow` anyException++data Init = Init+ { capacity :: {-# UNPACK #-} !Int,+ ref0 :: !(HMR.HashMap Int Int),+ hmM :: !(IO (HM.HashMap RealWorld Int))+ }++instance Show Init where+ show Init {..} = show (capacity, ref0)++instance QC.Arbitrary Init where+ arbitrary = do+ capacity <- QC.chooseInt (1, 10)+ pure $ Init capacity HMR.empty (HM.new capacity)++data Query+ = Size+ | Member Int+ | NotMember Int+ | Lookup Int+ | Insert Int Int+ | InsertWithAdd Int Int+ | Exchange Int Int+ | ModifyAdd Int Int+ | Clear+ deriving (Show)++instance QC.Arbitrary Query where+ arbitrary = do+ a <- QC.chooseInt (1, 100)+ if a == 1+ then pure Clear+ else+ QC.oneof+ [ pure Size,+ Member <$> keyGen,+ NotMember <$> keyGen,+ Lookup <$> keyGen,+ Insert <$> keyGen <*> valGen,+ InsertWithAdd <$> keyGen <*> valGen,+ Exchange <$> keyGen <*> valGen,+ ModifyAdd <$> keyGen <*> valGen+ ]+ where+ keyGen = QC.chooseInt (-5, 5)+ valGen = QC.chooseInt (-10, 10)++-- | Arbitrary return type for the `Query` result.+data Result+ = None+ | B Bool+ | I Int+ | M (Maybe Int)+ deriving (Show, Eq)++-- | containers. (referencial implementation)+handleRef :: HMR.HashMap Int Int -> Query -> (HMR.HashMap Int Int, Result)+handleRef hm q = case q of+ Size -> (hm, I $ HMR.size hm)+ Member k -> (hm, B $ HMR.member k hm)+ NotMember k -> (hm, B . not $ HMR.member k hm)+ Lookup k -> (hm, M $ HMR.lookup k hm)+ Insert k v -> (HMR.insert k v hm, None)+ InsertWithAdd k v -> (HMR.insertWith (+) k v hm, None)+ Exchange k v -> (HMR.insert k v hm, M $ HMR.lookup k hm)+ ModifyAdd k v -> (HMR.adjust (+ v) k hm, None)+ -- Delete k -> (HMR.delete k hm, HMR.lookup k hm)+ Clear -> (HMR.empty, None)++-- | ac-library-hs.+handleAcl :: (PrimMonad m) => HM.HashMap (PrimState m) Int -> Query -> m Result+handleAcl hm q = case q of+ Size -> I <$> HM.size hm+ Member k -> B <$> HM.member hm k+ NotMember k -> B <$> HM.notMember hm k+ Lookup k -> M <$> HM.lookup hm k+ Insert k v -> do+ HM.insert hm k v+ pure None+ InsertWithAdd k v -> do+ HM.insertWith hm (+) k v+ pure None+ Exchange k v -> M <$> HM.exchange hm k v+ ModifyAdd k v -> do+ HM.modify hm (+ v) k+ pure None+ -- Delete k -> HM.delete hm k+ Clear -> do+ HM.clear hm+ pure None++-- | Ensures the capacity limit.+passQuery :: Int -> HMR.HashMap Int Int -> Query -> Bool+passQuery limit is (Insert k _) = HMR.member k is || HMR.size is < limit+passQuery limit is (InsertWithAdd k _) = HMR.member k is || HMR.size is < limit+passQuery limit is (Exchange k _) = HMR.member k is || HMR.size is < limit+passQuery _ _ _ = True++prop_randomTest :: Init -> QC.Property+prop_randomTest Init {..} = QCM.monadicIO $ do+ hm <- QCM.run hmM+ q <- QCM.pick $ QC.chooseInt (1, 5 * capacity)+ qs <- QCM.pick $ QC.vectorOf q (QC.arbitrary @Query)+ foldM_+ ( \ref query -> do+ if passQuery capacity ref query+ then do+ let (!ref', !expected) = handleRef ref query+ res <- QCM.run $ handleAcl hm query+ QCM.assertWith (expected == res) $ show (query, expected, res)++ -- check the map contents:+ let assocsE = VU.modify (VAI.sortBy compare) . VU.fromList $ HMR.toList ref'+ assocs <- QCM.run $ VU.modify (VAI.sortBy compare) <$> HM.unsafeAssocs hm+ QCM.assertWith (assocsE == assocs) $ show ("- assocs", assocsE, assocs)++ let keysE = VU.modify (VAI.sortBy compare) . VU.fromList $ HMR.keys ref'+ keys <- QCM.run $ VU.modify (VAI.sortBy compare) <$> HM.unsafeKeys hm+ QCM.assertWith (keysE == keys) $ show ("- keys", keysE, keys)++ let elemsE = VU.modify (VAI.sortBy compare) . VU.fromList $ HMR.elems ref'+ elems <- QCM.run $ VU.modify (VAI.sortBy compare) <$> HM.unsafeElems hm+ QCM.assertWith (elemsE == elems) $ show ("- elems", elemsE, elems)++ let sizeE = HMR.size ref'+ size <- QCM.run $ HM.size hm+ QCM.assertWith (sizeE == size) $ show ("- size", sizeE, size)++ pure ref'+ else pure ref+ )+ ref0+ qs++tests :: [TestTree]+tests =+ [ unsafePerformIO spec_invalid,+ QC.testProperty "random test" prop_randomTest+ ]
+ test/Tests/Extra/IntMap.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.IntMap where++import AtCoder.Extra.IntMap qualified as IM+import Control.Monad (foldM_)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (RealWorld)+import Data.Map.Strict qualified as IMR -- R: referencial implementation+import Data.Vector.Unboxed qualified as VU+import GHC.Stack (HasCallStack)+import Test.QuickCheck.Monadic as QCM+import Test.Tasty+import Test.Tasty.QuickCheck as QC++data Init = Init+ { n :: {-# UNPACK #-} !Int,+ ref0 :: !(IMR.Map Int Int),+ imM :: !(IO (IM.IntMap RealWorld Int))+ }++instance Show Init where+ show Init {..} = show (n, ref0)++instance QC.Arbitrary Init where+ arbitrary = do+ n <- QC.chooseInt (1, 10)+ pure $ Init n IMR.empty (IM.new n)++data Query+ = Size+ | Member Int+ | NotMember Int+ | Null+ | Lookup Int+ | Insert Int Int+ | InsertWithAdd Int Int+ | Delete Int+ | Delete_ Int+ | LookupGE Int+ | LookupGT Int+ | LookupLE Int+ | LookupLT Int+ | LookupMin+ | LookupMax+ | DeleteMin+ | DeleteMax+ deriving (Show)++-- | Arbitrary return type for the `Query` result.+data Result+ = None+ | B Bool+ | I Int+ | M (Maybe Int)+ | KV (Maybe (Int, Int))+ | XS (VU.Vector Int)+ | KVS (VU.Vector (Int, Int))+ deriving (Show, Eq)++queryGen :: Int -> QC.Gen Query+queryGen n = do+ QC.oneof+ [ pure Size,+ Member <$> lookupKeyGen,+ NotMember <$> lookupKeyGen,+ pure Null,+ Lookup <$> lookupKeyGen,+ -- insert is partial function+ Insert <$> insertKeyGen <*> valGen,+ InsertWithAdd <$> insertKeyGen <*> valGen,+ Delete <$> lookupKeyGen,+ Delete_ <$> lookupKeyGen,+ LookupGE <$> lookupKeyGen,+ LookupGT <$> lookupKeyGen,+ LookupLE <$> lookupKeyGen,+ LookupLT <$> lookupKeyGen,+ pure LookupMin,+ pure LookupMax+ ]+ where+ -- for total functions+ lookupKeyGen = QC.chooseInt (-1, n)+ -- for partial functions+ insertKeyGen = QC.chooseInt (0, n - 1)+ valGen = QC.chooseInt (-10, 10)++-- | containers. (referencial implementation)+handleRef :: IMR.Map Int Int -> Query -> (IMR.Map Int Int, Result)+handleRef im q = case q of+ Size -> (im, I $ IMR.size im)+ Member k -> (im, B $ IMR.member k im)+ NotMember k -> (im, B . not $ IMR.member k im)+ Null -> (im, B $ IMR.null im)+ Lookup k -> (im, M $ IMR.lookup k im)+ Insert k v -> (IMR.insert k v im, None)+ InsertWithAdd k v -> (IMR.insertWith (+) k v im, None)+ Delete k -> (IMR.delete k im, B $ IMR.member k im)+ Delete_ k -> (IMR.delete k im, None)+ LookupGE k -> (im, KV (IMR.lookupGE k im))+ LookupGT k -> (im, KV (IMR.lookupGT k im))+ LookupLE k -> (im, KV (IMR.lookupLE k im))+ LookupLT k -> (im, KV (IMR.lookupLT k im))+ LookupMin -> (im, KV (IMR.lookupMin im))+ LookupMax -> (im, KV (IMR.lookupMax im))+ DeleteMin -> wrapKV IMR.deleteFindMin+ DeleteMax -> wrapKV IMR.deleteFindMax+ where+ wrapKV f+ | IMR.null im = (im, KV Nothing)+ | otherwise = let (!kv, !im') = f im in (im', KV (Just kv))++-- | ac-library-hs.+handleAcl :: (HasCallStack, PrimMonad m) => IM.IntMap (PrimState m) Int -> Query -> m Result+handleAcl im q = case q of+ Size -> I <$> IM.size im+ Member k -> B <$> IM.member im k+ NotMember k -> B <$> IM.notMember im k+ Null -> B <$> IM.null im+ Lookup k -> M <$> IM.lookup im k+ Insert k v -> do+ IM.insert im k v+ pure None+ InsertWithAdd k v -> do+ IM.insertWith im (+) k v+ pure None+ Delete k -> B <$> IM.delete im k+ Delete_ k -> do+ IM.delete_ im k+ pure None+ LookupGE k -> KV <$> IM.lookupGE im k+ LookupGT k -> KV <$> IM.lookupGT im k+ LookupLE k -> KV <$> IM.lookupLE im k+ LookupLT k -> KV <$> IM.lookupLT im k+ LookupMin -> KV <$> IM.lookupMin im+ LookupMax -> KV <$> IM.lookupMax im+ DeleteMin -> KV <$> IM.deleteMin im+ DeleteMax -> KV <$> IM.deleteMax im++prop_randomTest :: Init -> QC.Property+prop_randomTest Init {..} = QCM.monadicIO $ do+ im <- QCM.run imM+ q <- QCM.pick $ QC.chooseInt (1, 5 * n)+ qs <- QCM.pick $ QC.vectorOf q (queryGen n)+ foldM_+ ( \ref query -> do+ let (!ref', !expected) = handleRef ref query+ res <- QCM.run $ handleAcl im query+ QCM.assertWith (expected == res) $ show (query, expected, res)++ -- check the map contents:+ let assocsE = VU.fromList $ IMR.assocs ref'+ assocs <- QCM.run $ IM.assocs im+ QCM.assertWith (assocsE == assocs) $ show ("- assocs", assocsE, assocs)++ let keysE = VU.fromList $ IMR.keys ref'+ keys <- QCM.run $ IM.keys im+ QCM.assertWith (keysE == keys) $ show ("- keys", keysE, keys)++ let elemsE = VU.fromList $ IMR.elems ref'+ elems <- QCM.run $ IM.elems im+ QCM.assertWith (elemsE == elems) $ show ("- elems", elemsE, elems)++ let sizeE = IMR.size ref'+ size <- QCM.run $ IM.size im+ QCM.assertWith (sizeE == size) $ show ("- size", sizeE, size)++ pure ref'+ )+ ref0+ qs++tests :: [TestTree]+tests =+ [ QC.testProperty "randomTest" prop_randomTest+ ]
+ test/Tests/Extra/IntSet.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.IntSet where++import AtCoder.Extra.IntSet qualified as IS+import Control.Monad (foldM_)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (RealWorld)+import Data.Set qualified as ISR -- R: referencial implementation+import Data.Vector.Unboxed qualified as VU+import GHC.Stack (HasCallStack)+import Test.QuickCheck.Monadic as QCM+import Test.Tasty+import Test.Tasty.QuickCheck as QC++data Init = Init+ { n :: {-# UNPACK #-} !Int,+ ref0 :: !(ISR.Set Int),+ isM :: !(IO (IS.IntSet RealWorld))+ }++instance Show Init where+ show Init {..} = show (n, ref0)++instance QC.Arbitrary Init where+ arbitrary = do+ n <- QC.chooseInt (1, 10)+ pure $ Init n ISR.empty (IS.new n)++data Query+ = Member Int+ | NotMember Int+ | Null+ | Insert Int+ | Delete Int+ | Delete_ Int+ | LookupGE Int+ | LookupGT Int+ | LookupLE Int+ | LookupLT Int+ | LookupMin+ | LookupMax+ | DeleteMin+ | DeleteMax+ deriving (Show)++-- | Arbitrary return type for the `Query` result.+data Result+ = None+ | B Bool+ | I Int+ | M (Maybe Int)+ deriving (Show, Eq)++queryGen :: Int -> QC.Gen Query+queryGen n = do+ QC.oneof+ [ Member <$> lookupKeyGen,+ NotMember <$> lookupKeyGen,+ pure Null,+ -- insert is partial function+ Insert <$> insertKeyGen,+ Delete <$> lookupKeyGen,+ Delete_ <$> lookupKeyGen,+ LookupGE <$> lookupKeyGen,+ LookupGT <$> lookupKeyGen,+ LookupLE <$> lookupKeyGen,+ LookupLT <$> lookupKeyGen,+ pure LookupMin,+ pure LookupMax+ ]+ where+ -- for total functions+ lookupKeyGen = QC.chooseInt (-1, n)+ -- for partial functions+ insertKeyGen = QC.chooseInt (0, n - 1)++-- | containers. (referencial implementation)+handleRef :: ISR.Set Int -> Query -> (ISR.Set Int, Result)+handleRef is q = case q of+ Member k -> (is, B $ ISR.member k is)+ NotMember k -> (is, B . not $ ISR.member k is)+ Null -> (is, B $ ISR.null is)+ Insert k -> (ISR.insert k is, None)+ Delete k -> (ISR.delete k is, B $ ISR.member k is)+ Delete_ k -> (ISR.delete k is, None)+ LookupGE k -> (is, M (ISR.lookupGE k is))+ LookupGT k -> (is, M (ISR.lookupGT k is))+ LookupLE k -> (is, M (ISR.lookupLE k is))+ LookupLT k -> (is, M (ISR.lookupLT k is))+ LookupMin -> (is, M (ISR.lookupMin is))+ LookupMax -> (is, M (ISR.lookupMax is))+ DeleteMin -> wrapK ISR.deleteFindMin+ DeleteMax -> wrapK ISR.deleteFindMax+ where+ wrapK f+ | ISR.null is = (is, M Nothing)+ | otherwise = let (!kv, !is') = f is in (is', M (Just kv))++-- | ac-library-hs.+handleAcl :: (HasCallStack, PrimMonad m) => IS.IntSet (PrimState m) -> Query -> m Result+handleAcl is q = case q of+ Member k -> B <$> IS.member is k+ NotMember k -> B <$> IS.notMember is k+ Null -> B <$> IS.null is+ Insert k -> do+ IS.insert is k+ pure None+ Delete k -> B <$> IS.delete is k+ Delete_ k -> do+ IS.delete_ is k+ pure None+ LookupGE k -> M <$> IS.lookupGE is k+ LookupGT k -> M <$> IS.lookupGT is k+ LookupLE k -> M <$> IS.lookupLE is k+ LookupLT k -> M <$> IS.lookupLT is k+ LookupMin -> M <$> IS.lookupMin is+ LookupMax -> M <$> IS.lookupMax is+ DeleteMin -> M <$> IS.deleteMin is+ DeleteMax -> M <$> IS.deleteMax is++prop_randomTest :: Init -> QC.Property+prop_randomTest Init {..} = QCM.monadicIO $ do+ is <- QCM.run isM+ q <- QCM.pick $ QC.chooseInt (1, 5 * n)+ qs <- QCM.pick $ QC.vectorOf q (queryGen n)+ foldM_+ ( \ref query -> do+ let (!ref', !expected) = handleRef ref query+ res <- QCM.run $ handleAcl is query+ QCM.assertWith (expected == res) $ show (query, expected, res)++ -- check the set contents:+ let keysE = VU.fromList $ ISR.elems ref'+ keys <- QCM.run $ IS.keys is+ QCM.assertWith (keysE == keys) $ show ("- keys", keysE, keys)++ let sizeE = ISR.size ref'+ size <- QCM.run $ IS.size is+ QCM.assertWith (sizeE == size) $ show ("- size", sizeE, size)++ pure ref'+ )+ ref0+ qs++tests :: [TestTree]+tests =+ [ QC.testProperty "randomTest" prop_randomTest+ ]
+ test/Tests/Extra/IntervalMap.hs view
@@ -0,0 +1,209 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.IntervalMap where++import AtCoder.Extra.IntervalMap qualified as ITM+import AtCoder.Internal.Buffer qualified as ACIB+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (RealWorld, runST)+import Data.Foldable (for_)+import Data.List qualified as L+import Data.Map qualified as M+import Data.Primitive.MutVar+import Data.Vector.Generic.Mutable qualified as VGM+import Data.Vector.Unboxed qualified as VU+import Data.Vector.Unboxed.Mutable qualified as VUM+import Test.QuickCheck.Monadic as QCM+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck as QC+import Tests.Util (intervalGen)++-- | buildM should call onAdd and onDel correctly+prop_buildM :: QC.Gen QC.Property+prop_buildM = do+ n <- QC.chooseInt (1, 10)+ xs <- QC.vectorOf n (QC.chooseInt (-1, 1))++ let groups = VU.group $ VU.fromList xs+ let lens = L.scanl' (+) (0 :: Int) $ map VU.length groups+ let expected = VU.fromList $ L.zip3 lens (tail lens) (L.map VU.head groups)++ let res = runST $ do+ buf <- ACIB.new @_ @(Int, Int, Int) n+ _ <- ITM.buildM (VU.fromList xs) $ \l r x -> do+ ACIB.pushBack buf (l, r, x)+ ACIB.freeze buf++ pure $ res QC.=== expected++data Init = Init+ { n :: {-# UNPACK #-} !Int,+ refM :: !(IO (VUM.MVector RealWorld Int)),+ itmM :: !(IO (ITM.IntervalMap RealWorld Int))+ }++instance Show Init where+ show Init {..} = show ("Init", n)++instance QC.Arbitrary Init where+ arbitrary = do+ n <- QC.chooseInt (1, 20)+ pure $ Init n (VUM.replicate n undef) (ITM.new n)++data Query+ = Contains Int+ | Intersects (Int, Int)+ | Lookup (Int, Int)+ | -- | Read (Int, Int)+ ReadMaybe (Int, Int)+ | Insert (Int, Int) Int+ | Delete (Int, Int)+ | Overwrite (Int, Int) Int+ | Freeze+ | TestFreq+ deriving (Show)++-- | Arbitrary return type for the `Query` result.+data Result+ = None+ | B Bool+ | I Int+ | LRX (Maybe (Int, Int, Int))+ | M (Maybe Int)+ | XS (VU.Vector (Int, (Int, Int)))+ | -- | Counts (len * (len + 1) / 2) for each interval and sum them up.+ Freq (M.Map Int Int)+ deriving (Show, Eq)++queryGen :: Int -> QC.Gen Query+queryGen n = do+ QC.oneof+ [ Contains <$> keyGen,+ Intersects <$> intervalGen n,+ Lookup <$> intervalGen n,+ ReadMaybe <$> intervalGen n,+ Insert <$> intervalGen n <*> valGen,+ Delete <$> intervalGen n,+ Overwrite <$> intervalGen n <*> valGen,+ pure Freeze+ -- TestFreq is manually given+ -- pure TestFreq+ ]+ where+ keyGen = QC.chooseInt (0, n - 1)+ valGen = QC.chooseInt (-20, 20)++undef :: Int+undef = minBound `div` 2++-- | Half-open intervals.+toIntervals :: (PrimMonad m) => VUM.MVector (PrimState m) Int -> m (VU.Vector (Int, Int, Int))+toIntervals vec = do+ vec' <- VU.freeze vec+ let groups = VU.group vec'+ let lens = L.scanl' (+) (0 :: Int) $ map VU.length groups+ let intervals = zipWith (\xs l -> (l, l + VU.length xs, VU.head xs)) groups lens+ pure . VU.fromList $ filter (\(!_, !_, !x) -> x /= undef) intervals++-- | containers. (referencial implementation)+handleRef :: (PrimMonad m) => VUM.MVector (PrimState m) Int -> Query -> m Result+handleRef vec q = do+ intervals <- toIntervals vec+ case q of+ Contains i -> do+ pure . B $ VU.any (\(!l, !r, !_) -> l <= i && i < r) intervals+ Intersects (!l, !r)+ | l >= r -> pure $ B False+ | otherwise -> pure . B $ VU.any (\(!l', !r', !_) -> l' <= l && r <= r') intervals+ Lookup (!l, !r)+ | l >= r -> pure $ LRX Nothing+ | otherwise -> pure . LRX $ VU.find (\(!l', !r', !_) -> l' <= l && r <= r') intervals+ ReadMaybe (!l, !r)+ | l >= r -> pure $ M Nothing+ | otherwise -> pure $ maybe (M Nothing) (M . Just . (\(!_, !_, !x) -> x)) $ VU.find (\(!l', !r', !_) -> l' <= l && r <= r') intervals+ Insert (!l, !r) x -> do+ for_ [l .. r - 1] $ \i -> do+ VGM.write vec i x+ pure None+ Delete (!l, !r) -> do+ for_ [l .. r - 1] $ \i -> do+ VGM.write vec i undef+ pure None+ Overwrite (!l, !r) x+ | l >= r -> pure None+ | otherwise -> do+ let interval = VU.find (\(!l', !r', !_) -> l' <= l && r <= r') intervals+ case interval of+ Just (!l', !r', !_) -> do+ for_ [l' .. r' - 1] $ \i -> do+ VGM.write vec i x+ _ -> pure ()+ pure None+ Freeze -> pure . XS $ VU.map (\(!l, !r, !x) -> (l, (r, x))) intervals+ TestFreq -> pure . Freq . M.fromListWith (+) . VU.toList $ VU.map (\(!l, !r, !x) -> (x, (r - l) * ((r - l) + 1) `div` 2)) intervals++-- | ac-library-hs.+handleAcl :: (HasCallStack, PrimMonad m) => MutVar (PrimState m) (M.Map Int Int) -> ITM.IntervalMap (PrimState m) Int -> Query -> m Result+handleAcl freq itm q = case q of+ Contains i -> do+ B <$> ITM.contains itm i+ Intersects (!l, !r) -> do+ B <$> ITM.intersects itm l r+ Lookup (!l, !r) -> do+ LRX <$> ITM.lookup itm l r+ ReadMaybe (!l, !r) -> do+ M <$> ITM.readMaybe itm l r+ Insert (!l, !r) x -> do+ ITM.insertM itm l r x onAdd onDel+ pure None+ Delete (!l, !r) -> do+ ITM.deleteM itm l r onAdd onDel+ pure None+ Overwrite (!l, !r) x -> do+ ITM.overwriteM itm l r x onAdd onDel+ pure None+ Freeze -> do+ XS . VU.map (\(!l, (!r, !x)) -> (l, (r, x))) <$> ITM.freeze itm+ TestFreq -> Freq <$> readMutVar freq+ where+ onAdd l r x = do+ let len = r - l+ let delta = len * (len + 1) `div` 2+ modifyMutVar freq $ M.insertWith (+) x delta+ onDel l r x = modifyMutVar freq $ \m -> do+ let len = r - l+ let delta = len * (len + 1) `div` 2+ case M.lookup x m of+ Just n+ | n - delta == 0 -> M.delete x m+ | otherwise -> M.insert x (n - delta) m+ Nothing -> M.insert x delta m++prop_randomTest :: Init -> QC.Property+prop_randomTest Init {..} = QCM.monadicIO $ do+ ref <- QCM.run refM+ im <- QCM.run itmM+ freq <- QCM.run $ newMutVar M.empty+ q <- QCM.pick $ QC.chooseInt (1, 10 * n)+ qs <- QCM.pick $ QC.vectorOf q (queryGen n)+ for_ qs $ \query -> do+ expected <- QCM.run $ handleRef ref query+ res <- QCM.run $ handleAcl freq im query+ QCM.assertWith (expected == res) $ show (query, expected, res)++ -- always test Freq as an invariant+ expectedI <- QCM.run $ handleRef ref Freeze+ resI <- QCM.run $ handleAcl freq im Freeze+ QCM.assertWith (expectedI == resI) $ show (Freeze, expectedI, resI)++ -- always test Freq as an invariant+ expectedF <- QCM.run $ handleRef ref TestFreq+ resF <- QCM.run $ handleAcl freq im TestFreq+ QCM.assertWith (expectedF == resF) $ show (TestFreq, expectedF, resF)++tests :: [TestTree]+tests =+ [ QC.testProperty "buildM" prop_buildM,+ QC.testProperty "randomTest" prop_randomTest+ ]
test/Tests/Extra/Monoid.hs view
@@ -1,7 +1,11 @@ module Tests.Extra.Monoid (tests) where import AtCoder.Extra.Monoid-import Data.Bit (Bit(..))+import AtCoder.Extra.Monoid.Affine1 qualified as A+import AtCoder.Extra.Monoid.Mat2x2 qualified as M+import AtCoder.Extra.Monoid.RollingHash (RollingHash (..))+import AtCoder.ModInt qualified as ModInt+import Data.Bit (Bit (..)) import Data.Proxy (Proxy (..)) import Data.Semigroup (Max (..), Min (..), Product (..), Sum (..), stimes) import Test.QuickCheck.Classes qualified as QCC@@ -71,10 +75,6 @@ arbitrary = RangeAdd <$> QC.arbitrary -- orphan instance-instance (QC.Arbitrary a) => QC.Arbitrary (RangeAddId a) where- arbitrary = RangeAddId <$> QC.arbitrary---- orphan instance instance (QC.Arbitrary a, Monoid a) => QC.Arbitrary (RangeSet a) where arbitrary = do b <- (== 1) <$> QC.chooseInt (1, 30)@@ -83,12 +83,19 @@ else pure mempty -- orphan instance-instance (QC.Arbitrary a, Monoid a) => QC.Arbitrary (RangeSetId a) where+instance (QC.Arbitrary a) => QC.Arbitrary (Mat2x2 a) where+ arbitrary = Mat2x2 <$> QC.arbitrary++-- orphan instance+instance (QC.Arbitrary a) => QC.Arbitrary (V2 a) where+ arbitrary = V2 <$> QC.arbitrary++-- orphan instance+instance QC.Arbitrary (RollingHash b 998244353) where arbitrary = do- b <- (== 1) <$> QC.chooseInt (1, 30)- if b- then RangeSetId . (Bit True,) <$> QC.arbitrary- else pure mempty+ hash <- QC.chooseInt (0, 998244353 - 1)+ next <- QC.chooseInt (0, 998244353 - 1)+ pure $ RollingHash hash next -- orphan instance instance QC.Arbitrary (Max Int) where@@ -98,11 +105,53 @@ instance QC.Arbitrary (Min Int) where arbitrary = Min <$> QC.arbitrary +-- orphan instance (TODO: move to common implementation)+instance QC.Arbitrary ModInt.ModInt998244353 where+ arbitrary = ModInt.new <$> QC.arbitrary++prop_affineZero :: Affine1 (Sum Int) -> QC.Property+prop_affineZero a =+ QC.conjoin+ [ A.zero <> a QC.=== A.zero,+ a <> A.zero QC.=== (\(A.Affine1 (!_, !b)) -> A.Affine1 (0, b)) a+ ]++prop_affineIdent :: Affine1 (Sum Int) -> QC.Property+prop_affineIdent a =+ QC.conjoin+ [ A.ident <> a QC.=== a,+ a <> A.ident QC.=== a+ ]++prop_mat2x2Zero :: Mat2x2 Int -> QC.Property+prop_mat2x2Zero a =+ QC.conjoin+ [ M.zero <> a QC.=== M.zero,+ a <> M.zero QC.=== M.zero+ ]++prop_mat2x2Ident :: Mat2x2 Int -> QC.Property+prop_mat2x2Ident a =+ QC.conjoin+ [ M.ident <> a QC.=== a,+ a <> M.ident QC.=== a+ ]++prop_mat2x2Inv :: Mat2x2 ModInt.ModInt998244353 -> QC.Property+prop_mat2x2Inv a =+ (M.det a /= 0 QC.==>) $+ QC.conjoin+ [ M.inv a <> a QC.=== M.ident,+ a <> M.inv a QC.=== M.ident+ ]+ tests :: [TestTree] tests = [ testGroup "Affine1"- [ laws @(Affine1 (Sum Int))+ [ QC.testProperty "zero" prop_affineZero,+ QC.testProperty "ident" prop_affineIdent,+ laws @(Affine1 (Sum Int)) [ QCC.semigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws@@ -113,26 +162,28 @@ ], testGroup "RangeAdd"- [ laws @(RangeAdd Int)+ [ laws @(RangeAdd (Sum Int)) [ QCC.semigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws ],- laws @(RangeAdd Int, Sum Int)+ laws @(RangeAdd (Sum Int), Sum Int) [ segActLaw- ]- ],- testGroup- "RangeAddId"- [ laws @(RangeAddId Int)+ ],+ laws @(RangeAdd (Max Int)) [ QCC.semigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws ],- laws @(RangeAddId Int, Max Int)+ laws @(RangeAdd (Max Int), Max Int) [ segActLaw ],- laws @(RangeAddId Int, Min Int)+ laws @(RangeAdd (Min Int))+ [ QCC.semigroupLaws,+ QCC.monoidLaws,+ QCC.semigroupMonoidLaws+ ],+ laws @(RangeAdd (Min Int), Min Int) [ segActLaw ] ],@@ -143,65 +194,62 @@ QCC.monoidLaws, QCC.semigroupMonoidLaws ],+ laws @(RangeSet (Sum Int), Sum Int)+ [ segActLaw+ ], laws @(RangeSet (Product Int)) [ QCC.semigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws ],+ laws @(RangeSet (Product Int), Product Int)+ [ segActLaw+ ], laws @(RangeSet (Max Int)) [ QCC.semigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws ],+ laws @(RangeSet (Max Int), Max Int)+ [ segActLaw+ ], laws @(RangeSet (Min Int)) [ QCC.semigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws ],- laws @(RangeSet (Sum Int), Sum Int)- [ segActLaw- ],- laws @(RangeSet (Product Int), Product Int)- [ segActLaw- ],- laws @(RangeSet (Max Int), Max Int)- [ segActLaw- ], laws @(RangeSet (Min Int), Min Int) [ segActLaw ] ], testGroup- "RangeSetId"- [ laws @(RangeSetId (Sum Int))+ "Mat2x2"+ [ QC.testProperty "zero" prop_mat2x2Zero,+ QC.testProperty "ident" prop_mat2x2Ident,+ QC.testProperty "inv" prop_mat2x2Inv,+ laws @(Mat2x2 Int) [ QCC.semigroupLaws,- QCC.idempotentSemigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws ],- laws @(RangeSetId (Product Int))+ laws @(Mat2x2 Int, V2 Int)+ [ segActLaw+ ]+ ],+ testGroup+ "V2"+ [ laws @(V2 Int) [ QCC.semigroupLaws,- QCC.idempotentSemigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws- ],- laws @(RangeSetId (Max Int))+ ]+ ],+ testGroup+ "RollingHash"+ [ laws @(RollingHash 100 998244353) [ QCC.semigroupLaws,- QCC.idempotentSemigroupLaws, QCC.monoidLaws, QCC.semigroupMonoidLaws- ],- laws @(RangeSetId (Min Int))- [ QCC.semigroupLaws,- QCC.idempotentSemigroupLaws,- QCC.monoidLaws,- QCC.semigroupMonoidLaws- ],- laws @(RangeSetId (Max Int), Max Int)- [ segActLaw- ],- laws @(RangeSetId (Min Int), Min Int)- [ segActLaw ] ] ]
+ test/Tests/Extra/MultiSet.hs view
@@ -0,0 +1,218 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.MultiSet (tests) where++import AtCoder.Extra.MultiSet qualified as MS+import Control.Monad (foldM_, when)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (RealWorld)+import Data.IntMap qualified as IM+import Data.IntSet qualified as IS+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Unboxed qualified as VU+import System.IO.Unsafe (unsafePerformIO)+import Test.Hspec+import Test.QuickCheck.Monadic as QCM+import Test.Tasty+import Test.Tasty.Hspec+import Test.Tasty.QuickCheck as QC++spec_invalid :: IO TestTree+spec_invalid = testSpec "capacity limit" $ do+ it "throws error 1" $ do+ ms <- MS.new @_ 1+ MS.inc ms 0+ MS.inc ms 0+ MS.inc ms 1 `shouldThrow` anyException++ it "throws error 2" $ do+ ms <- MS.new @_ 2+ MS.inc ms 0+ MS.inc ms 1+ MS.inc ms 2 `shouldThrow` anyException++ it "throws error 2" $ do+ ms <- MS.new @_ 2+ MS.inc ms 0+ MS.inc ms 1+ MS.delete ms 1+ MS.inc ms 2 `shouldThrow` anyException++data Init = Init+ { n :: {-# UNPACK #-} !Int,+ ref0 :: !(IM.IntMap Int),+ msM :: !(IO (MS.MultiSet RealWorld))+ }++instance Show Init where+ show Init {..} = show (n, ref0)++instance QC.Arbitrary Init where+ arbitrary = do+ n <- QC.chooseInt (1, 10)+ pure $ Init n IM.empty (MS.new n)++data Query+ = Member Int+ | NotMember Int+ | Lookup Int+ | Inc Int+ | -- Safe* are performed to not create negative count+ SafeDec Int+ | SafeAdd Int Int+ | SafeSub Int Int+ | Insert Int Int+ | Delete Int+ deriving (Show)++-- | Arbitrary return type for the `Query` result.+data Result+ = None+ | B Bool+ | I Int+ | M (Maybe Int)+ deriving (Show, Eq)++queryGen :: Int -> QC.Gen Query+queryGen n = do+ QC.oneof+ [ Member <$> keyGen,+ NotMember <$> keyGen,+ Lookup <$> keyGen,+ Inc <$> keyGen,+ SafeDec <$> keyGen,+ SafeAdd <$> keyGen <*> deltaGen,+ SafeSub <$> keyGen <*> deltaGen,+ Insert <$> keyGen <*> insertValGen,+ Delete <$> keyGen+ ]+ where+ keyGen = QC.chooseInt (-n, n)+ deltaGen = QC.chooseInt (-n, n)+ insertValGen = QC.chooseInt (1, n)++-- | containers. (referencial implementation)+handleRef :: IM.IntMap Int -> Query -> (IM.IntMap Int, Result)+handleRef im q = case q of+ Member key -> (im, B $ IM.member key im)+ NotMember key -> (im, B $ IM.notMember key im)+ Lookup key -> (im, M $ IM.lookup key im)+ Inc key -> (IM.insertWith (+) key 1 im, None)+ SafeDec key -> case IM.lookup key im of+ Just 1 -> (IM.delete key im, None)+ Just n -> (IM.insert key (n - 1) im, None)+ Nothing -> (im, None)+ SafeAdd key dx -> case IM.lookup key im of+ Just n | n + dx == 0 -> (IM.delete key im, None)+ Just n | n + dx > 0 -> (IM.insert key (n + dx) im, None)+ Nothing | dx > 0 -> (IM.insert key dx im, None)+ _ -> (im, None)+ SafeSub key dx -> case IM.lookup key im of+ Just n | n - dx == 0 -> (IM.delete key im, None)+ Just n | n - dx > 0 -> (IM.insert key (n - dx) im, None)+ Nothing | -dx > 0 -> (IM.insert key (-dx) im, None)+ _ -> (im, None)+ Insert key val -> (IM.insert key val im, None)+ Delete key -> (IM.delete key im, None)++-- | ac-library-hs.+handleAcl :: (HasCallStack, PrimMonad m) => MS.MultiSet (PrimState m) -> Query -> m Result+handleAcl ms q = case q of+ Member key -> B <$> MS.member ms key+ NotMember key -> B <$> MS.notMember ms key+ Lookup key -> M <$> MS.lookup ms key+ Inc key -> do+ MS.inc ms key+ pure None+ SafeDec key -> do+ b <- MS.member ms key+ when b $ do+ MS.dec ms key+ pure None+ SafeAdd key dx -> do+ MS.lookup ms key >>= \case+ Just n | n + dx >= 0 -> do+ MS.add ms key dx+ Nothing | dx >= 0 -> do+ MS.add ms key dx+ _ -> pure ()+ pure None+ SafeSub key dx -> do+ MS.lookup ms key >>= \case+ Just n | n - dx >= 0 -> do+ MS.sub ms key dx+ Nothing | -dx >= 0 -> do+ MS.sub ms key dx+ _ -> pure ()+ pure None+ Insert key val -> do+ MS.insert ms key val+ pure None+ Delete key -> do+ MS.delete ms key+ pure None++-- | Ensures the capacity limit.+passQuery :: Int -> IS.IntSet -> Query -> Bool+passQuery limit is (Inc k) = IS.member k is || IS.size is < limit+passQuery limit is (SafeAdd k dx) = IS.member k is || IS.size is < limit || dx <= 0+passQuery limit is (SafeSub k dx) = IS.member k is || IS.size is < limit || dx >= 0+passQuery limit is (Insert k _) = IS.member k is || IS.size is < limit+passQuery _ _ _ = True++-- | Records used keys.+recordKey :: IS.IntSet -> Query -> IS.IntSet+recordKey is (Inc k) = IS.insert k is+recordKey is (SafeAdd k dx) | dx > 0 = IS.insert k is+recordKey is (SafeSub k dx) | dx < 0 = IS.insert k is+recordKey is (Insert k _) = IS.insert k is+recordKey is _ = is++-- TODO: record used key++prop_randomTest :: Init -> QC.Property+prop_randomTest Init {..} = QCM.monadicIO $ do+ ms <- QCM.run msM+ q <- QCM.pick $ QC.chooseInt (1, 5 * n)+ qs <- QCM.pick $ QC.vectorOf q (queryGen n)++ foldM_+ ( \(!ref, !keys) query -> do+ if passQuery n keys query+ then do+ -- run the query+ let (!ref', !expected) = handleRef ref query+ res <- QCM.run $ handleAcl ms query+ QCM.assertWith (expected == res) $ show (query, expected, res)++ -- check the map contents:+ let assocsE = VU.modify (VAI.sortBy compare) (VU.fromList (IM.assocs ref'))+ assocs <- QCM.run $ VU.modify (VAI.sortBy compare) <$> MS.unsafeAssocs ms+ QCM.assertWith (assocsE == assocs) $ show ("- assocs", assocsE, assocs)++ let keysE = VU.modify (VAI.sortBy compare) (VU.fromList (IM.keys ref'))+ keys_ <- QCM.run $ VU.modify (VAI.sortBy compare) <$> MS.unsafeKeys ms+ QCM.assertWith (keysE == keys_) $ show ("- keys", keysE, keys_)++ let elemsE = VU.modify (VAI.sortBy compare) (VU.fromList (IM.elems ref'))+ elems <- QCM.run $ VU.modify (VAI.sortBy compare) <$> MS.unsafeElems ms+ QCM.assertWith (elemsE == elems) $ show ("- elems", elemsE, elems)++ let sizeE = IM.size ref'+ size <- QCM.run $ MS.size ms+ QCM.assertWith (sizeE == size) $ show ("- size", sizeE, size)++ pure (ref', recordKey keys query)+ else+ pure (ref, keys)+ )+ (ref0, IS.empty)+ qs++-- TODO: test invariant++tests :: [TestTree]+tests =+ [ unsafePerformIO spec_invalid,+ QC.testProperty "random test" prop_randomTest+ ]
+ test/Tests/Extra/Semigroup/Matrix.hs view
@@ -0,0 +1,43 @@+module Tests.Extra.Semigroup.Matrix (tests) where++import AtCoder.Extra.Semigroup.Matrix qualified as Mat+import AtCoder.ModInt qualified as M+import Data.Vector.Unboxed qualified as VU+import GHC.TypeNats (KnownNat)+import Test.QuickCheck.Classes qualified as QCC+import Test.Tasty+import Test.Tasty.QuickCheck qualified as QC+import Tests.Util (laws)++-- TODO: (const True) should be removed++-- orphan instance+instance (QC.Arbitrary a, VU.Unbox a) => QC.Arbitrary (Mat.Matrix a) where+ -- for simplicity, make a 33x33 matrix+ arbitrary = do+ let n = 33+ vec <- VU.fromList <$> QC.vectorOf (n * n) (QC.arbitrary @a)+ pure $ Mat.Matrix n n vec++-- orphan instance+instance (KnownNat p) => QC.Arbitrary (M.ModInt p) where+ arbitrary = M.new <$> QC.arbitrary++prop_mulToCol :: QC.Gen QC.Property+prop_mulToCol = do+ h <- QC.chooseInt (1, 16)+ w <- QC.chooseInt (1, 16)+ vec <- VU.fromList <$> QC.vectorOf (h * w) (QC.arbitrary @Int)+ let mat = Mat.new h w vec+ col <- VU.fromList <$> QC.vectorOf w (QC.arbitrary @Int)+ let lhs = Mat.mulToCol mat col+ let rhs = Mat.vecM $ Mat.mul mat (Mat.new w 1 col)+ pure $ lhs QC.=== rhs++tests :: [TestTree]+tests =+ [ QC.testProperty "mulToCol" prop_mulToCol,+ laws @(Mat.Matrix (M.ModInt 998244353))+ [ QCC.semigroupLaws+ ]+ ]
+ test/Tests/Extra/Semigroup/Permutation.hs view
@@ -0,0 +1,71 @@+module Tests.Extra.Semigroup.Permutation (tests) where++import AtCoder.Extra.Semigroup.Permutation qualified as P+import Control.Exception (evaluate)+import Data.Vector.Unboxed qualified as VU+import System.IO.Unsafe (unsafePerformIO)+import Test.Hspec+import Test.QuickCheck.Classes qualified as QCC+import Test.Tasty+import Test.Tasty.Hspec+import Test.Tasty.QuickCheck as QC+import Tests.Util (laws)++spec_invalid :: IO TestTree+spec_invalid = testSpec "boundary check" $ do+ let !_ = P.new $ VU.fromList [0]+ let !_ = P.new $ VU.fromList [-1] -- -1 is allowed+ it "throws error 1" $ do+ evaluate (P.new (VU.fromList [1])) `shouldThrow` anyException+ it "throws error 2" $ do+ evaluate (P.new (VU.fromList [-2])) `shouldThrow` anyException++prop_ident :: P.Permutation -> QC.Property+prop_ident p =+ QC.conjoin+ [ p <> ident QC.=== p,+ ident <> p QC.=== p+ ]+ where+ ident = P.ident (P.length p)++prop_zero :: P.Permutation -> QC.Property+prop_zero p =+ QC.conjoin+ [ p <> zero QC.=== zero,+ zero <> p QC.=== zero+ ]+ where+ zero = P.zero (P.length p)++prop_identAct :: QC.Positive Int -> QC.Gen QC.Property+prop_identAct (QC.Positive len) = do+ let p = P.ident len+ i <- QC.chooseInt (0, len - 1)+ pure $ P.act p i QC.=== i++prop_zeroAct :: QC.Positive Int -> QC.Gen QC.Property+prop_zeroAct (QC.Positive len) = do+ let p = P.zero len+ i <- QC.chooseInt (0, len - 1)+ pure $ P.act p i QC.=== i++-- orphan instance+instance QC.Arbitrary P.Permutation where+ arbitrary = do+ let n = 33+ vec <- VU.fromList <$> QC.vectorOf n (QC.chooseInt (-1, n - 1))+ pure $ P.new vec++tests :: [TestTree]+tests =+ [ unsafePerformIO spec_invalid,+ QC.testProperty "ident" prop_ident,+ QC.testProperty "zero" prop_zero,+ QC.testProperty "identAct" prop_identAct,+ QC.testProperty "zeroAct" prop_zeroAct,+ laws+ @P.Permutation+ [ QCC.semigroupLaws+ ]+ ]
+ test/Tests/Extra/WaveletMatrix.hs view
@@ -0,0 +1,237 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.WaveletMatrix (tests) where++import AtCoder.Extra.WaveletMatrix qualified as WM+import Data.IntMap qualified as IM+import Data.Ord (comparing)+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Unboxed qualified as VU+import Test.Hspec+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck as QC+import Tests.Util (intervalGen)++data Init = Init+ { capacity :: {-# UNPACK #-} !Int,+ xs :: !(VU.Vector Int),+ wm :: !WM.WaveletMatrix+ }++instance Show Init where+ show Init {..} = show ("Init", capacity, xs)++instance QC.Arbitrary Init where+ arbitrary = do+ QC.NonNegative n <- QC.arbitrary+ xs <- VU.fromListN n <$> QC.vectorOf n (QC.arbitrary @Int)+ pure $ Init n xs (WM.build xs)++data Query+ = Access !Int+ | KthSmallestIn !(Int, Int) !Int+ | IKthSmallestIn !(Int, Int) !Int+ | KthLargestIn !(Int, Int) !Int+ | IKthLargestIn !(Int, Int) !Int+ | RankBetween !(Int, Int) !(Int, Int)+ | Rank !(Int, Int) !Int+ | Select !Int+ | SelectIn !(Int, Int) !Int+ | SelectKth !Int !Int+ | SelectKthIn !(Int, Int) !Int !Int+ | LookupLE !(Int, Int) !Int+ | LookupLT !(Int, Int) !Int+ | LookupGE !(Int, Int) !Int+ | LookupGT !(Int, Int) !Int+ | AssocsIn !(Int, Int)+ | DescAssocsIn !(Int, Int)+ deriving (Show)++genQuery :: Int -> QC.Gen Query+genQuery n = do+ QC.oneof+ [ Access <$> QC.chooseInt (-1, n),+ KthSmallestIn <$> lr <*> exc,+ IKthSmallestIn <$> lr <*> exc,+ KthLargestIn <$> lr <*> exc,+ IKthLargestIn <$> lr <*> exc,+ RankBetween <$> lr <*> lr,+ Rank <$> lr <*> val,+ Select <$> val,+ SelectIn <$> lr <*> val,+ SelectKth <$> exc <*> val,+ SelectKthIn <$> lr <*> exc <*> val,+ LookupLE <$> lr <*> QC.chooseInt (-1, n),+ LookupLT <$> lr <*> QC.chooseInt (-1, n),+ LookupGE <$> lr <*> QC.chooseInt (-1, n),+ LookupGT <$> lr <*> QC.chooseInt (-1, n),+ AssocsIn <$> lr,+ DescAssocsIn <$> lr+ ]+ where+ exc = QC.chooseInt (0, n)+ lr = intervalGen n+ val = QC.chooseInt (-n, n)++-- | Arbitrary return type for the `Query` result.+data Result+ = I {-# UNPACK #-} !Int+ | M !(Maybe Int)+ | M2 !(Maybe (Int, Int))+ | Assocs [(Int, Int)]+ deriving (Show, Eq)++-- | containers. (referencial implementation)+handleRef :: VU.Vector Int -> Query -> Result+handleRef xs q = case q of+ Access i -> M $ xs VU.!? i+ KthSmallestIn (!l, !r) k -> M $ snd <$> ikthSmallestIn l r k+ IKthSmallestIn (!l, !r) k -> M2 $ ikthSmallestIn l r k+ KthLargestIn (!l, !r) k -> M $ snd <$> ikthLargestIn l r k+ IKthLargestIn (!l, !r) k -> M2 $ ikthLargestIn l r k+ RankBetween (!l, !r) (!xl, !xr) -> rankBetween l r xl xr+ Rank (!l, !r) x -> rankBetween l r x (x + 1)+ Select x -> M $ selectKthIn 0 n 0 x+ SelectIn (!l, !r) x -> M $ selectKthIn l r 0 x+ SelectKth k x -> M $ selectKthIn 0 n k x+ SelectKthIn (!l, !r) k x -> M $ selectKthIn l r k x+ LookupLE (!l, !r) x -> max_ . VU.filter (<= x) . VU.take (r - l) $ VU.drop l xs+ LookupLT (!l, !r) x -> max_ . VU.filter (< x) . VU.take (r - l) $ VU.drop l xs+ LookupGE (!l, !r) x -> min_ . VU.filter (>= x) . VU.take (r - l) $ VU.drop l xs+ LookupGT (!l, !r) x -> min_ . VU.filter (> x) . VU.take (r - l) $ VU.drop l xs+ AssocsIn (!l, !r) -> Assocs . IM.assocs . IM.fromListWith (+) . VU.toList . VU.map (,1) . VU.take (r - l) $ VU.drop l xs+ DescAssocsIn (!l, !r) -> Assocs . reverse . IM.assocs . IM.fromListWith (+) . VU.toList . VU.map (,1) . VU.take (r - l) $ VU.drop l xs+ where+ n = VU.length xs+ max_ ys+ | VU.null ys = M Nothing+ | otherwise = M $ Just $ VU.maximum ys+ min_ ys+ | VU.null ys = M Nothing+ | otherwise = M $ Just $ VU.minimum ys+ ikthSmallestIn l r k =+ (VU.!? k)+ . VU.modify (VAI.sortBy (comparing (\(!i, !x) -> (x, i))))+ . VU.take (r - l)+ . VU.drop l+ . VU.indexed+ $ xs+ ikthLargestIn l r k = ikthSmallestIn l r ((r - l) - (k + 1))+ rankBetween l r xl xr =+ I+ . VU.length+ . VU.filter (\x -> xl <= x && x < xr)+ . VU.take (r - l)+ . VU.drop l+ $ xs+ selectKthIn l r k x =+ (fst <$>)+ . (VU.!? k)+ . VU.filter ((== x) . snd)+ . VU.take (r - l)+ . VU.drop l+ . VU.indexed+ $ xs++handleAcl :: WM.WaveletMatrix -> Query -> Result+handleAcl wm q = case q of+ Access i -> M $ WM.access wm i+ KthSmallestIn (!l, !r) k -> M $ WM.kthSmallestIn wm l r k+ IKthSmallestIn (!l, !r) k -> M2 $ WM.ikthSmallestIn wm l r k+ KthLargestIn (!l, !r) k -> M $ WM.kthLargestIn wm l r k+ IKthLargestIn (!l, !r) k -> M2 $ WM.ikthLargestIn wm l r k+ RankBetween (!l, !r) (!xl, !xr) -> I $ WM.rankBetween wm l r xl xr+ Rank (!l, !r) x -> I $ WM.rankBetween wm l r x (x + 1)+ Select x -> M $ WM.select wm x+ SelectIn (!l, !r) x -> M $ WM.selectIn wm l r x+ SelectKth k x -> M $ WM.selectKth wm k x+ SelectKthIn (!l, !r) k x -> M $ WM.selectKthIn wm l r k x+ LookupLE (!l, !r) x -> M $ WM.lookupLE wm l r x+ LookupLT (!l, !r) x -> M $ WM.lookupLT wm l r x+ LookupGE (!l, !r) x -> M $ WM.lookupGE wm l r x+ LookupGT (!l, !r) x -> M $ WM.lookupGT wm l r x+ AssocsIn (!l, !r) -> Assocs $ WM.assocsIn wm l r+ DescAssocsIn (!l, !r) -> Assocs $ WM.descAssocsIn wm l r++prop_randomTest :: Init -> QC.Gen QC.Property+prop_randomTest Init {..} = do+ qs <- QC.vectorOf capacity (genQuery capacity)+ pure . QC.conjoin $+ map+ ( \q ->+ QC.counterexample (show q) $+ handleRef xs q QC.=== handleAcl wm q+ )+ qs++unit_boundary :: TestTree+unit_boundary = testCase "boundary" $ do+ let n = 5+ let wm = WM.build $ VU.fromList [0, 10, 20, 10, 0]++ let try :: (HasCallStack, Eq a, Show a) => (WM.WaveletMatrix -> Int -> Int -> Int -> Maybe a) -> Int -> IO ()+ try f x = do+ (@?= Nothing) $ f wm (-1) 0 x+ (@?= Nothing) $ f wm 20 (20 + 1) x++ let k = 0+ try WM.kthSmallestIn k+ try WM.ikthSmallestIn k+ try WM.kthLargestIn k+ try WM.ikthLargestIn k++-- try WM.unsafeKthSmallestIn+-- try WM.unsafeIKthSmallestIn+-- try WM.unsafeKthLargestIn+-- try WM.unsafeIKthLargestIn++ let tryRank :: (HasCallStack) => (WM.WaveletMatrix -> Int -> Int -> Int -> Int) -> Int -> IO ()+ tryRank f x = do+ -- out of range+ (@?= 0) $ f wm (-1) 0 x+ (@?= 0) $ f wm n (n + 1) x+ -- reverse+ (@?= 0) $ f wm 1 0 x+ (@?= 0) $ f wm n (n - 1) x+ (@?= 0) $ f wm n 0 x+ -- out of range and reverse+ (@?= 0) $ f wm 0 (-1) x+ (@?= 0) $ f wm (n + 1) n x++ let tryRankBetween :: (HasCallStack) => (WM.WaveletMatrix -> Int -> Int -> Int -> Int -> Int) -> Int -> Int -> IO ()+ tryRankBetween f xl xr = do+ -- out of range+ (@?= 0) $ f wm (-1) 0 xl xr+ (@?= 0) $ f wm n (n + 1) xl xr+ -- reverse+ (@?= 0) $ f wm 1 0 xl xr+ (@?= 0) $ f wm n (n - 1) xl xr+ (@?= 0) $ f wm n 0 xl xr+ -- out of range and reverse+ (@?= 0) $ f wm 0 (-1) xl xr+ (@?= 0) $ f wm (n + 1) n xl xr++ tryRankBetween WM.rankBetween (-1) 1+ tryRank WM.rank 0+ tryRank WM.rank 1+ tryRank WM.rank (-1)++-- TODO: test ++-- (@?= Nothing) $ WM.select wm+-- (@?= Nothing) $ WM.selectKth wm+-- (@?= Nothing) $ WM.selectKthIn wm++-- (@?= Nothing) $ WM.lookupLE wm+-- (@?= Nothing) $ WM.lookupLT wm+-- (@?= Nothing) $ WM.lookupGE wm+-- (@?= Nothing) $ WM.lookupGT wm+-- (@?= Nothing) $ WM.assocsIn wm+-- (@?= Nothing) $ WM.descAssocsIn wm++tests :: [TestTree]+tests =+ [ unit_boundary,+ QC.testProperty "random test" prop_randomTest+ ]
+ test/Tests/Extra/WaveletMatrix/BitVector.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.WaveletMatrix.BitVector where++import AtCoder.Extra.WaveletMatrix.BitVector qualified as BV+import Data.Bit (Bit (..))+import Data.Vector.Unboxed qualified as VU+import Test.Tasty+import Test.Tasty.QuickCheck as QC+import Tests.Util (intervalGen)++data Init = Init+ { capacity :: {-# UNPACK #-} !Int,+ ref :: !(VU.Vector Bool),+ bv :: !BV.BitVector+ }+ deriving (Eq, Show)++instance QC.Arbitrary Init where+ arbitrary = do+ QC.Positive capacity <- QC.arbitrary+ bs <- QC.vectorOf capacity (QC.arbitrary @Bool)+ pure $ Init capacity (VU.fromList bs) (BV.build (VU.fromList (map Bit bs)))++data Query+ = Rank0 {-# UNPACK #-} !Int+ | Rank1 {-# UNPACK #-} !Int+ | Select0 {-# UNPACK #-} !Int+ | Select1 {-# UNPACK #-} !Int+ | SelectKth0 {-# UNPACK #-} !(Int, Int) !Int+ | SelectKth1 {-# UNPACK #-} !(Int, Int) !Int+ deriving (Show)++genQuery :: Int -> QC.Gen Query+genQuery n = do+ QC.oneof+ [ Rank0 <$> QC.chooseInt (0, n),+ Rank1 <$> QC.chooseInt (0, n),+ Select0 <$> QC.chooseInt (0, n),+ Select1 <$> QC.chooseInt (0, n),+ SelectKth0 <$> intervalGen n <*> QC.chooseInt (0, n),+ SelectKth1 <$> intervalGen n <*> QC.chooseInt (0, n)+ ]++-- | Arbitrary return type for the `Query` result.+data Result+ = I {-# UNPACK #-} !Int+ | M !(Maybe Int)+ deriving (Show, Eq)++-- | containers. (referencial implementation)+handleRef :: VU.Vector Bool -> Query -> Result+handleRef xs q = case q of+ Rank0 k -> I . VU.length . VU.filter not $ VU.take k xs+ Rank1 k -> I . VU.length . VU.filter id $ VU.take k xs+ Select0 k -> M . (fst <$>) . (VU.!? k) . VU.filter (not . snd) $ VU.indexed xs+ Select1 k -> M . (fst <$>) . (VU.!? k) . VU.filter snd $ VU.indexed xs+ SelectKth0 (!l, !r) k -> M . (fst <$>) . (VU.!? k) . VU.filter (not . snd) . VU.take (r - l) . VU.drop l $ VU.indexed xs+ SelectKth1 (!l, !r) k -> M . (fst <$>) . (VU.!? k) . VU.filter snd . VU.take (r - l) . VU.drop l $ VU.indexed xs++handleAcl :: BV.BitVector -> Query -> Result+handleAcl bv q = case q of+ Rank0 k -> I $ BV.rank0 bv k+ Rank1 k -> I $ BV.rank1 bv k+ Select0 k -> M $ BV.select0 bv k+ Select1 k -> M $ BV.select1 bv k+ SelectKth0 (!l, !r) k -> M $ BV.selectKthIn0 bv l r k+ SelectKth1 (!l, !r) k -> M $ BV.selectKthIn1 bv l r k++prop_randomTest :: Init -> QC.Gen QC.Property+prop_randomTest Init {..} = do+ qs <- QC.vectorOf capacity (genQuery capacity)+ pure . QC.conjoin $+ map+ ( \q ->+ QC.counterexample (show q) $+ handleRef ref q QC.=== handleAcl bv q+ )+ qs++tests :: [TestTree]+tests =+ [ QC.testProperty "random test" prop_randomTest+ ]
+ test/Tests/Extra/WaveletMatrix/Raw.hs view
@@ -0,0 +1,271 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.WaveletMatrix.Raw (tests) where++import AtCoder.Extra.Bisect (lowerBound)+import AtCoder.Extra.WaveletMatrix.Raw qualified as WM+import Control.Exception (evaluate)+import Data.IntMap qualified as IM+import Data.Maybe (fromJust)+import Data.Ord (comparing)+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Unboxed qualified as VU+import System.IO.Unsafe (unsafePerformIO)+import Test.Hspec+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.Hspec+import Test.Tasty.QuickCheck as QC+import Tests.Util (intervalGen)++compress :: VU.Vector Int -> VU.Vector Int+compress xs =+ let dict = VU.uniq $ VU.modify VAI.sort xs+ in VU.map (fromJust . lowerBound dict) xs++data Init = Init+ { capacity :: {-# UNPACK #-} !Int,+ xs :: !(VU.Vector Int),+ wm :: !WM.RawWaveletMatrix+ }+ deriving (Eq, Show)++instance QC.Arbitrary Init where+ arbitrary = do+ QC.NonNegative n <- QC.arbitrary+ xs <- compress . VU.fromListN n <$> QC.vectorOf n (QC.arbitrary @Int)+ pure $ Init n xs (WM.build n xs)++data Query+ = Access !Int+ | KthSmallestIn !(Int, Int) !Int+ | IKthSmallestIn !(Int, Int) !Int+ | KthLargestIn !(Int, Int) !Int+ | IKthLargestIn !(Int, Int) !Int+ | UnsafeKthSmallestIn !(Int, Int) !Int+ | UnsafeIKthSmallestIn !(Int, Int) !Int+ | UnsafeKthLargestIn !(Int, Int) !Int+ | UnsafeIKthLargestIn !(Int, Int) !Int+ | RankLT !(Int, Int) !Int+ | RankBetween !(Int, Int) !(Int, Int)+ | Rank !(Int, Int) !Int+ | Select !Int+ | SelectKth !Int !Int+ | SelectKthIn !(Int, Int) !Int !Int+ | LookupLE !(Int, Int) !Int+ | LookupLT !(Int, Int) !Int+ | LookupGE !(Int, Int) !Int+ | LookupGT !(Int, Int) !Int+ | AssocsIn !(Int, Int)+ | DescAssocsIn !(Int, Int)+ deriving (Show)++genQuery :: Int -> QC.Gen Query+genQuery n = do+ QC.oneof+ [ Access <$> QC.chooseInt (-1, n),+ KthSmallestIn <$> lr <*> exc,+ IKthSmallestIn <$> lr <*> exc,+ KthLargestIn <$> lr <*> exc,+ IKthLargestIn <$> lr <*> exc,+ UnsafeKthSmallestIn <$> lr <*> inc,+ UnsafeIKthSmallestIn <$> lr <*> inc,+ UnsafeKthLargestIn <$> lr <*> inc,+ UnsafeIKthLargestIn <$> lr <*> inc,+ RankLT <$> lr <*> val,+ RankBetween <$> lr <*> lr,+ Rank <$> lr <*> val,+ Select <$> val,+ SelectKth <$> exc <*> val,+ SelectKthIn <$> lr <*> exc <*> val,+ LookupLE <$> lr <*> QC.chooseInt (-1, n),+ LookupLT <$> lr <*> QC.chooseInt (-1, n),+ LookupGE <$> lr <*> QC.chooseInt (-1, n),+ LookupGT <$> lr <*> QC.chooseInt (-1, n),+ AssocsIn <$> lr,+ DescAssocsIn <$> lr+ ]+ where+ inc = QC.chooseInt (0, n - 1)+ exc = QC.chooseInt (0, n)+ lr = intervalGen n+ val = QC.chooseInt (-n, n)++-- | Arbitrary return type for the `Query` result.+data Result+ = I {-# UNPACK #-} !Int+ | M !(Maybe Int)+ | M2 !(Maybe (Int, Int))+ | Assocs [(Int, Int)]+ deriving (Show, Eq)++-- | containers. (referencial implementation)+handleRef :: VU.Vector Int -> Query -> Result+handleRef xs q = case q of+ Access i -> M $ xs VU.!? i+ KthSmallestIn (!l, !r) k -> M $ snd <$> ikthSmallestIn l r k+ IKthSmallestIn (!l, !r) k -> M2 $ ikthSmallestIn l r k+ KthLargestIn (!l, !r) k -> M $ snd <$> ikthLargestIn l r k+ IKthLargestIn (!l, !r) k -> M2 $ ikthLargestIn l r k+ UnsafeKthSmallestIn (!l, !r) k -> M $ snd <$> ikthSmallestIn l r k+ UnsafeIKthSmallestIn (!l, !r) k -> M2 $ ikthSmallestIn l r k+ UnsafeKthLargestIn (!l, !r) k -> M $ snd <$> ikthLargestIn l r k+ UnsafeIKthLargestIn (!l, !r) k -> M2 $ ikthLargestIn l r k+ RankLT (!l, !r) xr -> rankBetween l r (minBound `div` 2) xr+ RankBetween (!l, !r) (!xl, !xr) -> rankBetween l r xl xr+ Rank (!l, !r) x -> rankBetween l r x (x + 1)+ Select x -> M $ selectKthIn 0 n 0 x+ SelectKth k x -> M $ selectKthIn 0 n k x+ SelectKthIn (!l, !r) k x -> M $ selectKthIn l r k x+ LookupLE (!l, !r) x -> max_ . VU.filter (<= x) . VU.take (r - l) $ VU.drop l xs+ LookupLT (!l, !r) x -> max_ . VU.filter (< x) . VU.take (r - l) $ VU.drop l xs+ LookupGE (!l, !r) x -> min_ . VU.filter (>= x) . VU.take (r - l) $ VU.drop l xs+ LookupGT (!l, !r) x -> min_ . VU.filter (> x) . VU.take (r - l) $ VU.drop l xs+ AssocsIn (!l, !r) -> Assocs . IM.assocs . IM.fromListWith (+) . VU.toList . VU.map (,1) . VU.take (r - l) $ VU.drop l xs+ DescAssocsIn (!l, !r) -> Assocs . reverse . IM.assocs . IM.fromListWith (+) . VU.toList . VU.map (,1) . VU.take (r - l) $ VU.drop l xs+ where+ n = VU.length xs+ max_ ys+ | VU.null ys = M Nothing+ | otherwise = M $ Just $ VU.maximum ys+ min_ ys+ | VU.null ys = M Nothing+ | otherwise = M $ Just $ VU.minimum ys+ ikthSmallestIn l r k =+ (VU.!? k)+ . VU.modify (VAI.sortBy (comparing (\(!i, !x) -> (x, i))))+ . VU.take (r - l)+ . VU.drop l+ . VU.indexed+ $ xs+ ikthLargestIn l r k = ikthSmallestIn l r ((r - l) - (k + 1))+ rankBetween l r xl xr =+ I+ . VU.length+ . VU.filter (\x -> xl <= x && x < xr)+ . VU.take (r - l)+ . VU.drop l+ $ xs+ selectKthIn l r k x =+ (fst <$>)+ . (VU.!? k)+ . VU.filter ((== x) . snd)+ . VU.take (r - l)+ . VU.drop l+ . VU.indexed+ $ xs++handleAcl :: WM.RawWaveletMatrix -> Query -> Result+handleAcl wm q = case q of+ Access i -> M $ WM.access wm i+ KthSmallestIn (!l, !r) k -> M $ WM.kthSmallestIn wm l r k+ IKthSmallestIn (!l, !r) k -> M2 $ WM.ikthSmallestIn wm l r k+ KthLargestIn (!l, !r) k -> M $ WM.kthLargestIn wm l r k+ IKthLargestIn (!l, !r) k -> M2 $ WM.ikthLargestIn wm l r k+ UnsafeKthSmallestIn (!l, !r) k -> M $ WM.kthSmallestIn wm l r k+ UnsafeIKthSmallestIn (!l, !r) k -> M2 $ WM.ikthSmallestIn wm l r k+ UnsafeKthLargestIn (!l, !r) k -> M $ WM.kthLargestIn wm l r k+ UnsafeIKthLargestIn (!l, !r) k -> M2 $ WM.ikthLargestIn wm l r k+ RankLT (!l, !r) xr -> I $ WM.rankLT wm l r xr+ RankBetween (!l, !r) (!xl, !xr) -> I $ WM.rankBetween wm l r xl xr+ Rank (!l, !r) x -> I $ WM.rank wm l r x+ Select x -> M $ WM.select wm x+ SelectKth k x -> M $ WM.selectKth wm k x+ SelectKthIn (!l, !r) k x -> M $ WM.selectKthIn wm l r k x+ LookupLE (!l, !r) x -> M $ WM.lookupLE wm l r x+ LookupLT (!l, !r) x -> M $ WM.lookupLT wm l r x+ LookupGE (!l, !r) x -> M $ WM.lookupGE wm l r x+ LookupGT (!l, !r) x -> M $ WM.lookupGT wm l r x+ AssocsIn (!l, !r) -> Assocs $ WM.assocsIn wm l r+ DescAssocsIn (!l, !r) -> Assocs $ WM.descAssocsIn wm l r++prop_randomTest :: Init -> QC.Gen QC.Property+prop_randomTest Init {..} = do+ qs <- QC.vectorOf capacity (genQuery capacity)+ pure . QC.conjoin $+ map+ ( \q ->+ QC.counterexample (show q) $+ handleRef xs q QC.=== handleAcl wm q+ )+ qs++unit_boundary :: TestTree+unit_boundary = testCase "boundary" $ do+ let n = 5+ let wm = WM.build 3 $ VU.fromList [0, 1, 2, 1, 0]++ let try :: (HasCallStack, Eq a, Show a) => (WM.RawWaveletMatrix -> Int -> Int -> Int -> Maybe a) -> Int -> IO ()+ try f x = do+ (@?= Nothing) $ f wm (-1) 0 x+ (@?= Nothing) $ f wm n (n + 1) x++ let k = 0+ try WM.kthSmallestIn k+ try WM.ikthSmallestIn k+ try WM.kthLargestIn k+ try WM.ikthLargestIn k++-- try WM.unsafeKthSmallestIn+-- try WM.unsafeIKthSmallestIn+-- try WM.unsafeKthLargestIn+-- try WM.unsafeIKthLargestIn++ let tryRank :: (HasCallStack) => (WM.RawWaveletMatrix -> Int -> Int -> Int -> Int) -> Int -> IO ()+ tryRank f x = do+ -- out of range+ (@?= 0) $ f wm (-1) 0 x+ (@?= 0) $ f wm n (n + 1) x+ -- reverse+ (@?= 0) $ f wm 1 0 x+ (@?= 0) $ f wm n (n - 1) x+ (@?= 0) $ f wm n 0 x+ -- out of range and reverse+ (@?= 0) $ f wm 0 (-1) x+ (@?= 0) $ f wm (n + 1) n x++ let tryRankBetween :: (HasCallStack) => (WM.RawWaveletMatrix -> Int -> Int -> Int -> Int -> Int) -> Int -> Int -> IO ()+ tryRankBetween f xl xr = do+ -- out of range+ (@?= 0) $ f wm (-1) 0 xl xr+ (@?= 0) $ f wm n (n + 1) xl xr+ -- reverse+ (@?= 0) $ f wm 1 0 xl xr+ (@?= 0) $ f wm n (n - 1) xl xr+ (@?= 0) $ f wm n 0 xl xr+ -- out of range and reverse+ (@?= 0) $ f wm 0 (-1) xl xr+ (@?= 0) $ f wm (n + 1) n xl xr++ tryRank WM.rankLT 0+ tryRank WM.rankLT 1+ tryRank WM.rankLT (-1)+ tryRankBetween WM.rankBetween (-1) 1+ tryRank WM.rank 0+ tryRank WM.rank 1+ tryRank WM.rank (-1)++-- TODO: test ++-- (@?= Nothing) $ WM.select wm+-- (@?= Nothing) $ WM.selectKth wm+-- (@?= Nothing) $ WM.selectKthIn wm++-- (@?= Nothing) $ WM.lookupLE wm+-- (@?= Nothing) $ WM.lookupLT wm+-- (@?= Nothing) $ WM.lookupGE wm+-- (@?= Nothing) $ WM.lookupGT wm+-- (@?= Nothing) $ WM.assocsIn wm+-- (@?= Nothing) $ WM.descAssocsIn wm++spec_invalid :: IO TestTree+spec_invalid = testSpec "boundary check" $ do+ it "throws error 1" $ do+ evaluate (WM.build (-1) (VU.singleton 1)) `shouldThrow` anyException++tests :: [TestTree]+tests =+ [ unit_boundary,+ unsafePerformIO spec_invalid,+ QC.testProperty "random test" prop_randomTest+ ]
+ test/Tests/Extra/WaveletMatrix2d.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE RecordWildCards #-}++module Tests.Extra.WaveletMatrix2d (tests) where++import AtCoder.Extra.WaveletMatrix2d qualified as WM+import Control.Monad (foldM_)+import Control.Monad.Primitive (PrimMonad, PrimState)+import Control.Monad.ST (RealWorld)+import Data.List qualified as L+import Data.Map qualified as M+import Data.Maybe (fromMaybe)+import Data.Ord (comparing)+import Data.Semigroup (Sum (..))+import Data.Vector.Algorithms.Intro qualified as VAI+import Data.Vector.Unboxed qualified as VU+import Test.Hspec+import Test.QuickCheck.Monadic as QCM+import Test.Tasty+import Test.Tasty.HUnit+import Test.Tasty.QuickCheck as QC+import Tests.Util (intervalGen)++data Init = Init+ { capacity :: {-# UNPACK #-} !Int,+ map0 :: !(M.Map (Int, Int) (Sum Int)),+ wmM :: !(IO (WM.WaveletMatrix2d RealWorld (Sum Int)))+ }++instance Show Init where+ show Init {..} = show ("Init", capacity, map0)++instance QC.Arbitrary Init where+ arbitrary = do+ QC.NonNegative n <- QC.arbitrary+ let yxs = VU.fromList [(x, y) | x <- [-16 .. 16], y <- [-16 .. 16]]+ pure $ Init n M.empty (WM.new negate yxs)++data Query+ = Read !(Int, Int)+ | Write !(Int, Int) !Int+ | ModifyAdd !Int !(Int, Int)+ | Prod !(Int, Int) !(Int, Int)+ | ProdMaybe !(Int, Int) !(Int, Int)+ | AllProd+ deriving (Show)++genQuery :: Int -> QC.Gen Query+genQuery n = do+ QC.oneof+ [ Read <$> lr,+ Write <$> lr <*> val,+ ModifyAdd <$> val <*> lr,+ Prod <$> lr <*> lr,+ ProdMaybe <$> lr <*> lr,+ pure AllProd+ ]+ where+ lr = (\(!x, !y) -> (x - 16, y - 16)) <$> intervalGen 32+ val = QC.arbitrary @Int++-- | Arbitrary return type for the `Query` result.+data Result+ = None+ | S !(Sum Int)+ | MS !(Maybe (Sum Int))+ deriving (Show, Eq)++-- | containers. (referencial implementation)+handleRef :: M.Map (Int, Int) (Sum Int) -> Query -> (Result, M.Map (Int, Int) (Sum Int))+handleRef map q = case q of+ Read (!x, !y) -> (S . fromMaybe mempty $ M.lookup (x, y) map, map)+ Write (!x, !y) v -> (None, M.insert (x, y) (Sum v) map)+ ModifyAdd w (!x, !y) -> (None, M.insertWith (+) (x, y) (Sum w) map)+ Prod (!x1, !x2) (!y1, !y2) -> (S $ prod x1 x2 y1 y2, map)+ ProdMaybe (!x1, !x2) (!y1, !y2) -> (MS . Just $ prod x1 x2 y1 y2, map)+ AllProd -> (S $ L.foldl' (<>) mempty (M.elems map), map)+ where+ prod x1 x2 y1 y2 =+ L.foldl' (<>) (mempty :: Sum Int)+ . (snd <$>)+ . filter (\((!x, !y), !_) -> x1 <= x && x < x2 && y1 <= y && y < y2)+ $ M.assocs map++handleAcl :: (PrimMonad m) => WM.WaveletMatrix2d (PrimState m) (Sum Int) -> Query -> m Result+handleAcl wm q = case q of+ Read (!x, !y) -> do+ S <$> WM.read wm (x, y)+ Write (!x, !y) v -> do+ WM.write wm (x, y) $ Sum v+ pure None+ ModifyAdd w (!x, !y) -> do+ WM.modify wm (+ Sum w) (x, y)+ pure None+ Prod (!x1, !x2) (!y1, !y2) -> do+ S <$> WM.prod wm x1 x2 y1 y2+ ProdMaybe (!x1, !x2) (!y1, !y2) -> do+ MS <$> WM.prodMaybe wm x1 x2 y1 y2+ AllProd -> do+ S <$> WM.allProd wm++prop_randomTest :: Init -> QC.Property+prop_randomTest Init {..} = QCM.monadicIO $ do+ wm <- QCM.run wmM+ qs <- QCM.pick $ QC.vectorOf capacity (genQuery capacity)+ foldM_+ ( \map query -> do+ let (!expected, !map') = handleRef map query+ actual <- QCM.run $ handleAcl wm query+ QCM.assertWith (expected == actual) $ show (query, expected, actual)+ pure map'+ )+ map0+ qs++tests :: [TestTree]+tests =+ [ -- unit_boundary,+ QC.testProperty "random test" prop_randomTest+ ]
test/Tests/MaxFlow.hs view
@@ -2,7 +2,7 @@ module Tests.MaxFlow (tests) where import AtCoder.MaxFlow qualified as MF-import Data.Bit (Bit(..))+import Data.Bit (Bit (..)) import Data.Vector.Unboxed qualified as VU import System.IO.Unsafe (unsafePerformIO) import Test.Hspec
test/Tests/Scc.hs view
@@ -1,5 +1,3 @@-{-# LANGUAGE RecordWildCards #-}- module Tests.Scc (tests) where import AtCoder.Scc qualified as Scc
test/Tests/Util.hs view
@@ -1,4 +1,4 @@-module Tests.Util (myForAllShrink, laws) where+module Tests.Util (myForAllShrink, laws, intervalGen) where import Data.Proxy (Proxy (..)) import Data.Typeable (Typeable, typeRep)@@ -40,3 +40,10 @@ let QCC.Laws name pairs = f (Proxy @a) in testGroup name (map (uncurry QC.testProperty) pairs) )++-- | Returns an interval [l, r) in [0, n)+intervalGen :: Int -> QC.Gen (Int, Int)+intervalGen n = do+ l <- QC.chooseInt (0, n)+ r <- QC.chooseInt (l, n)+ pure (l, r)