結果

問題 No.876 Range Compress Query
ユーザー yukimyyukimy
提出日時 2024-06-10 17:09:34
言語 Crystal
(1.11.2)
結果
AC  
実行時間 351 ms / 2,000 ms
コード長 3,142 bytes
コンパイル時間 15,966 ms
コンパイル使用メモリ 295,952 KB
実行使用メモリ 26,832 KB
最終ジャッジ日時 2024-06-10 17:09:58
合計ジャッジ時間 15,976 ms
ジャッジサーバーID
(参考情報)
judge2 / judge3
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
6,816 KB
testcase_01 AC 3 ms
6,812 KB
testcase_02 AC 2 ms
6,812 KB
testcase_03 AC 3 ms
6,940 KB
testcase_04 AC 2 ms
6,944 KB
testcase_05 AC 2 ms
6,940 KB
testcase_06 AC 3 ms
6,944 KB
testcase_07 AC 2 ms
6,940 KB
testcase_08 AC 3 ms
6,940 KB
testcase_09 AC 3 ms
6,940 KB
testcase_10 AC 2 ms
6,940 KB
testcase_11 AC 351 ms
26,204 KB
testcase_12 AC 264 ms
25,788 KB
testcase_13 AC 252 ms
26,288 KB
testcase_14 AC 310 ms
26,252 KB
testcase_15 AC 239 ms
22,012 KB
testcase_16 AC 303 ms
26,556 KB
testcase_17 AC 314 ms
22,284 KB
testcase_18 AC 336 ms
26,832 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#遅延評価セグ木

class LazySegmentTree(T)
  @sz : Int64
  #配列、単位元、単位元関数、二項演算、作用関数、作用合成関数をブロックで渡す
  def initialize(ary : Array(T), @e : Proc(T), @id : Proc(Act), @operator : T, T -> T, @mapping : Act, T -> T, @composition : Act, Act -> Act)
    @n = ary.size.to_i64
    sz = 1_i64
    while sz < @n
      sz *= 2
    end
    @tree = Array(T).new(sz*2-1,@e.call)
    @lazy = Array(Act).new(sz*2-1,@id.call)
    @sz = sz
    i = 0_i64
    #葉に元の値を入れる
    while i < sz
      if i >= @n
        @tree[i+sz-1] = @e.call
      else
        @tree[i+sz-1] = ary[i]
      end
      i += 1
    end
    i = sz - 2
    while i >= 0
      #親に上って子を比較しながら値を入れる
      @tree[i] = @operator.call(@tree[i*2+1], @tree[i*2+2])
      i -= 1
    end
  end

  def tree
    i = 0_i64
    while i < @sz - 1
      eval(i)
      i += 1
    end
    res = Array(Int64).new
    while i < @sz + @n - 1
      eval(i)
      res << @tree[i].val
      i += 1
    end
    return res
  end

  #indexを指定して返す
  def [] (i : Int64)
    get(i,i+1)
  end

  def eval(i : Int64)
    return if @lazy[i] == @id.call
    if i < @sz - 1
      #子に合成
      @lazy[i*2+1] = @composition.call(@lazy[i], @lazy[i*2+1])
      @lazy[i*2+2] = @composition.call(@lazy[i], @lazy[i*2+2])
    end
    #適用
    @tree[i] = @mapping.call(@lazy[i], @tree[i])
    #単位元関数に戻す
    @lazy[i] = @id.call
  end

  def update(a : Int64, b : Int64, f : Act, now = 0_i64, l = 0_i64, r = -1_i64)
    r = @sz if r < 0
    eval(now)
    return if (r <= a || b <= l)
    if a <= l && r <= b
      @lazy[now] = f
      eval(now)
    elsif (a < r && l < b)
      update(a,b,f,now*2+1,l,(l+r)//2)
      update(a,b,f,now*2+2,(l+r)//2,r)
      @tree[now] = @operator.call(@tree[now*2+1],@tree[now*2+2])
    end
  end

  def get(a : Int64, b : Int64, now = 0_i64, l = 0_i64, r = -1_i64)
    eval(now)
    r = @sz if r < 0
    return @e.call if (r <= a || b <= l)
    return @tree[now] if (a <= l && r <= b)
    vl = get(a,b,now*2+1,l,(l+r)//2)
    vr = get(a,b,now*2+2,(l+r)//2,r)
    return @operator.call(vl, vr)
  end    
end

#以下を事前に設定
record Node, l : Int64, r : Int64, v : Int64
record Act, x : Int64
op = -> (x : Node, y : Node) do
  if x.l == -1
    y
  elsif y.l == -1
    x
  else
    Node.new(x.l, y.r, x.v + y.v + (x.r == y.l ? 0 : 1))
  end
end
e = -> () { Node.new(-1_i64, -1_i64, 0_i64) }
mapping = -> (f : Act, x : Node) { Node.new(x.l + f.x, x.r + f.x, x.v) }
id = -> () { Act.new(0_i64) } # 引数が有意な関数と一致しないよう注意
composition = -> (g : Act, f : Act) { Act.new(g.x + f.x) } # g(f(x))になるように

n, q = read_line.split.map(&.to_i64)
a = read_line.split.map(&.to_i64)
ary = a.map { |v| Node.new(v, v, 0_i64) }
tree = LazySegmentTree(Node).new(ary, e, id, op, mapping, composition)
q.times do
  query = read_line.split.map(&.to_i64)
  t = query[0]
  l = query[1]
  r = query[2]
  if t == 1
    tree.update(l - 1, r, Act.new(query[3]))
  else
    puts tree.get(l - 1, r).v + 1
  end
end
0