結果

問題 No.879 Range Mod 2 Query
ユーザー yukimyyukimy
提出日時 2024-06-10 19:36:53
言語 Crystal
(1.11.2)
結果
AC  
実行時間 406 ms / 3,000 ms
コード長 3,805 bytes
コンパイル時間 12,579 ms
コンパイル使用メモリ 295,496 KB
実行使用メモリ 31,616 KB
最終ジャッジ日時 2024-06-10 19:37:12
合計ジャッジ時間 18,744 ms
ジャッジサーバーID
(参考情報)
judge3 / judge5
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
5,248 KB
testcase_01 AC 3 ms
5,248 KB
testcase_02 AC 3 ms
5,376 KB
testcase_03 AC 3 ms
5,376 KB
testcase_04 AC 4 ms
5,376 KB
testcase_05 AC 2 ms
5,376 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 3 ms
5,376 KB
testcase_08 AC 3 ms
5,376 KB
testcase_09 AC 2 ms
5,376 KB
testcase_10 AC 3 ms
5,376 KB
testcase_11 AC 361 ms
28,584 KB
testcase_12 AC 210 ms
28,544 KB
testcase_13 AC 280 ms
31,104 KB
testcase_14 AC 254 ms
29,184 KB
testcase_15 AC 254 ms
21,632 KB
testcase_16 AC 356 ms
29,056 KB
testcase_17 AC 383 ms
31,616 KB
testcase_18 AC 377 ms
31,616 KB
testcase_19 AC 406 ms
29,024 KB
testcase_20 AC 373 ms
31,616 KB
testcase_21 AC 373 ms
29,272 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, odd_sum : Int64, even_sum : Int64, odd_cnt : Int64, even_cnt : Int64
op = -> (x : Node, y : Node) { Node.new(x.odd_sum + y.odd_sum, x.even_sum + y.even_sum, x.odd_cnt + y.odd_cnt, x.even_cnt + y.even_cnt) }
e = -> () { Node.new(0_i64, 0_i64, 0_i64, 0_i64) }
record Act, q1 : Int64, q2 : Int64
mapping = -> (f : Act, x : Node) do
  v1 = x.odd_sum
  v2 = x.even_sum
  v3 = x.odd_cnt
  v4 = x.even_cnt
  if f.q1 == 1
    v1 = v3
    v2 = 0_i64
  elsif f.q1 == 2
    v1 = v4
    v2 = 0_i64
    v3, v4 = v4, v3
  end
  v1 += f.q2 * v3
  v2 += f.q2 * v4
  if f.q2.odd?
    v1, v2 = v2, v1
    v3, v4 = v4, v3
  end
  Node.new(v1, v2, v3, v4)
end
id = -> () { Act.new(0_i64, 0_i64) } # 引数が有意な関数と一致しないよう注意
composition = -> (g : Act, f : Act) do
  if g.q1 == 0
    Act.new(f.q1, g.q2 + f.q2)
  else
    x = false
    if f.q1 == 2
      x = true
    end
    if f.q2.odd?
      x ^= true
    end
    if g.q1 == 2
      x ^= true
    end
    Act.new((x ? 2_i64 : 1_i64), g.q2)
  end
end

n, q = read_line.split.map(&.to_i64)
a = read_line.split.map(&.to_i64)
ary = a.map { |v| v.odd? ? Node.new(v, 0_i64, 1_i64, 0_i64) : Node.new(0_i64, v, 0_i64, 1_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(1_i64, 0_i64))
  elsif t == 2
    tree.update(l - 1, r, Act.new(0_i64, query[3]))
  else
    x = tree.get(l - 1, r)
    puts x.odd_sum + x.even_sum
  end
end
0