module Data.Struct.Internal.LinkCut where
import Control.Exception
import Control.Monad
import Control.Monad.Primitive
import Control.Monad.ST
import Data.Struct.Internal
import Data.Struct.TH
#ifdef HLINT
#endif
makeStruct [d|
data LinkCut a s = LinkCut
{ path, parent, left, right :: !(LinkCut a s)
, value, summary :: a
}
|]
new :: (PrimMonad m, Monoid a) => a -> m (LinkCut a (PrimState m))
new a = st (newLinkCut Nil Nil Nil Nil a a)
cut :: (PrimMonad m, Monoid a) => LinkCut a (PrimState m) -> m ()
cut this = st $ do
access this
l <- get left this
unless (isNil l) $ do
set left this Nil
set parent l Nil
v <- getField value this
setField summary this v
link :: (PrimMonad m, Monoid a) => LinkCut a (PrimState m) -> LinkCut a (PrimState m) -> m ()
link v w = st $ do
access v
access w
set path v w
connected :: (PrimMonad m, Monoid a) => LinkCut a (PrimState m) -> LinkCut a (PrimState m) -> m Bool
connected v w = st $ (==) <$> root v <*> root w
cost :: (PrimMonad m, Monoid a) => LinkCut a (PrimState m) -> m a
cost v = st $ do
access v
getField summary v
root :: (PrimMonad m, Monoid a) => LinkCut a (PrimState m) -> m (LinkCut a (PrimState m))
root this = st $ do
access this
r <- leftmost this
splay r
return r
where
leftmost v = do
l <- get left v
if isNil l then return v
else leftmost l
up :: (PrimMonad m, Monoid a) => LinkCut a (PrimState m) -> m (LinkCut a (PrimState m))
up this = st $ do
access this
a <- get left this
if isNil a then return Nil
else do
p <- rightmost a
splay p
return p
where
rightmost v = do
p <- get right v
if isNil p then return v
else rightmost p
summarize :: Monoid a => LinkCut a s -> ST s a
summarize this
| isNil this = return mempty
| otherwise = getField summary this
access :: Monoid a => LinkCut a s -> ST s ()
access this = do
when (isNil this) $ throw NullPointerException
splay this
r <- get right this
unless (isNil r) $ do
set right this Nil
set parent r Nil
set path r this
l <- get left this
sl <- summarize l
v <- getField value this
setField summary this (sl `mappend` v)
go this
splay this
where
go v = do
w <- get path v
unless (isNil w) $ do
splay w
b <- get right w
unless (isNil b) $ do
set path b w
set parent b Nil
a <- get left w
sa <- summarize a
vw <- getField value w
sv <- getField summary v
set parent v w
set right w v
setField summary w (sa `mappend` vw `mappend` sv)
go w
splay :: Monoid a => LinkCut a s -> ST s ()
splay x = do
p <- get parent x
unless (isNil p) $ do
g <- get parent p
pl <- get left p
if isNil g then do
set parent p x
set parent x Nil
pp <- get path p
set path x pp
set path p Nil
sp <- getField summary p
setField summary x sp
if pl == x then do
c <- get right x
d <- get right p
unless (isNil c) $ set parent c p
set right x p
set left p c
sc <- summarize c
sd <- summarize d
vp <- getField value p
setField summary p (sc `mappend` vp `mappend` sd)
else do
b <- get left x
unless (isNil b) $ set parent b p
let a = pl
set left x p
set right p b
sa <- summarize a
sb <- summarize b
vp <- getField value p
setField summary p (sa `mappend` vp `mappend` sb)
else do
gg <- get parent g
gl <- get left g
sg <- getField summary g
setField summary x sg
set parent x gg
gp <- get path g
set path x gp
set path g Nil
if gl == p then do
if pl == x then do
b <- get right x
c <- get right p
d <- get right g
set parent p x
set parent g p
unless (isNil b) $ set parent b p
unless (isNil c) $ set parent c g
set right x p
set right p g
set left p b
set left g c
sb <- summarize b
vp <- getField value p
sc <- summarize c
vg <- getField value g
sd <- summarize d
let sg' = sc `mappend` vg `mappend` sd
setField summary g sg'
setField summary p (sb `mappend` vp `mappend` sg')
else do
let a = pl
b <- get left x
c <- get right x
d <- get right g
set parent p x
set parent g x
unless (isNil b) $ set parent b p
unless (isNil c) $ set parent c g
set left x p
set right x g
set right p b
set left g c
sa <- summarize a
vp <- getField value p
sb <- summarize b
setField summary p (sa `mappend` vp `mappend` sb)
sc <- summarize c
vg <- getField value g
sd <- summarize d
setField summary g (sc `mappend` vg `mappend` sd)
else if pl == x then do
let a = gl
b <- get left x
c <- get right x
d <- get right p
set parent g x
set parent p x
unless (isNil b) $ set parent b g
unless (isNil c) $ set parent c p
set left x g
set right x p
set right g b
set left p c
sa <- summarize a
vg <- getField value g
sb <- summarize b
setField summary g (sa `mappend` vg `mappend` sb)
sc <- summarize c
vp <- getField value p
sd <- summarize d
setField summary p (sc `mappend` vp `mappend` sd)
else do
let a = gl
let b = pl
c <- get left x
unless (isNil b) $ set parent b g
unless (isNil c) $ set parent c p
set parent p x
set parent g p
set left x p
set left p g
set right g b
set right p c
sa <- summarize a
vg <- getField value g
sb <- summarize b
vp <- getField value p
sc <- summarize c
let sg' = sa `mappend` vg `mappend` sb
setField summary g sg'
setField summary p (sg' `mappend` vp `mappend` sc)
unless (isNil gg) $ do
ggl <- get left gg
if ggl == g then set left gg x
else set right gg x
splay x