結果
| 問題 | No.876 Range Compress Query |
| コンテスト | |
| ユーザー |
Hirotaka Ohkubo
|
| 提出日時 | 2026-04-06 13:32:56 |
| 言語 | Haskell (9.14.1) |
| 結果 |
AC
|
| 実行時間 | 439 ms / 2,000 ms |
| コード長 | 3,061 bytes |
| 記録 | |
| コンパイル時間 | 8,735 ms |
| コンパイル使用メモリ | 211,200 KB |
| 実行使用メモリ | 137,600 KB |
| 最終ジャッジ日時 | 2026-04-06 13:33:12 |
| 合計ジャッジ時間 | 12,407 ms |
|
ジャッジサーバーID (参考情報) |
judge2_1 / judge1_1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 1 |
| other | AC * 18 |
コンパイルメッセージ
Loaded package environment from /home/judge/.ghc/x86_64-linux-9.14.1/environments/default [1 of 2] Compiling Main ( Main.hs, Main.o ) [2 of 2] Linking a.out
ソースコード
import Control.Monad
import qualified Data.ByteString.Char8 as BS
import Data.Char
import Data.List
import Control.Monad.ST
import Data.Array.ST
import Data.Bool
import Data.Maybe
main :: IO ()
main = do
[n, q] <- bsGetLnInts
as <- bsGetLnInts
qs <- replicateM q bsGetLnInts
let ans = yuki876 n q as qs
mapM_ print ans
bsGetLnInts :: IO [Int]
bsGetLnInts = unfoldr (BS.readInt . BS.dropWhile isSpace) <$> BS.getLine
yuki876 :: Int -> Int -> [Int] -> [[Int]] -> [Int]
yuki876 n _q as qs = runST $
do
d <- newListArray (0, n1) $ zipWith (-) as (0 : as) :: ST s (STUArray s Int Int)
st <- makeSegTree (+) 0 $ zipWith diff1 (0 : as) as :: ST s (SegTree (STUArray s) Int)
catMaybes <$> forM qs (action d st)
where
n1 = pred n
diff1 x y = bool 0 1 $ x /= y
action d st (1:l:r:x:_) = do
let l1 = pred l
dl1 <- (x +) <$> readArray d l1
writeArray d l1 dl1
setSegTree st l1 $ diff1 0 dl1
when (r < n) $ do
dr1 <- subtract x <$> readArray d r
writeArray d r dr1
setSegTree st r $ diff1 0 dr1
return Nothing
action d st (2:l:r:_) = Just . succ <$> querySegTree st l r
{-
a[1~n] 元データ
d[0~n-1] 一つ**次**との差分 d[i] = a[i+1] - a[i] ただし a[0] = 0 とする
st[0~n-1] 次と異なるとき1、の区間和セグメント木 st[i] = d[i] ? 1 : 0
クエリ1
a[l] が x 増えるので、d[l-1] が x 増える
a[r] が x 増えるので、d[r] が x 減る r = N についてやる必要なし
-}
data SegTree ar a = SegTree (a->a->a) a Int (ar Int a)
-- makeSegTree の実行に付ける型注釈 Uなしも可
-- ST s (SegTree (STUArray s) <VAL>)
-- ST s (SegTree (STUArray s) <VAL>)
makeSegTree :: MArray ar a m => (a->a->a) -> a -> [a] -> m (SegTree ar a)
makeSegTree op e xs = do
let len = length xs
let w = until (len <=) (2 *) 1
arr <- newArray (0, 2 * pred w) e
zipWithM_ (writeArray arr) [pred w ..] xs
forM_ [w-2, w-3 .. 0] (\k -> do
let kk1 = k + succ k
l <- readArray arr kk1
r <- readArray arr (succ kk1)
writeArray arr k (op l r)
)
return $ SegTree op e w arr
setSegTree :: MArray ar a m => SegTree ar a -> Int -> a -> m ()
setSegTree (SegTree op _ w arr) j x = updateLoop op arr (j + pred w) x
-- 内部関数
updateLoop _p arr 0 x = writeArray arr 0 x
updateLoop op arr i x = do
writeArray arr i x
y <- if even i then flip op x <$> readArray arr (pred i) else op x <$> readArray arr (succ i)
updateLoop op arr (div (pred i) 2) y
querySegTree :: MArray ar a m => SegTree ar a -> Int -> Int -> m a
querySegTree (SegTree op e w0 arr) a b = recur 0 w0 0
where
recur p w i -- p : i のカバーする範囲の下端添え字 / w : iがカバーする横幅 / i : 注目している物理配列の添え字
| q <= a || b <= p = return e
| a <= p && q <= b = readArray arr i
| otherwise = do
l <- recur p w2 j
r <- recur (p + w2) w2 $ succ j
return (op l r)
where
q = p + w
w2 = div w 2
j = i + succ i
Hirotaka Ohkubo