結果

問題 No.876 Range Compress Query
コンテスト
ユーザー Hirotaka Ohkubo
提出日時 2026-04-06 13:32:56
言語 Haskell
(9.14.1)
コンパイル:
ghc -rtsopts -with-rtsopts=-K1G -o a.out -O2 _filename_
実行:
./a.out
結果
AC  
実行時間 439 ms / 2,000 ms
コード長 3,061 bytes
記録
記録タグの例:
初AC ショートコード 純ショートコード 純主流ショートコード 最速実行時間
コンパイル時間 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

ソースコード

diff #
raw source code

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
0