ngng628's Library

This documentation is automatically generated by online-judge-tools/verification-helper

:heavy_check_mark: verify/data_structure/dynamic_range_sum.test.cr

Depends on

Code

# verification-helper: PROBLEM https://judge.yosupo.jp/problem/point_add_range_sum

require "../../src/nglib/data_structure/dynamic_range_sum"

_n, q = read_line.split.map &.to_i64
a = read_line.split.map &.to_i64

csum = NgLib::DynamicRangeSum(Int64).new(a)

q.times do
  t, a, b = read_line.split.map &.to_i64
  case t
  when 0
    csum.add(a, b)
  when 1
    puts csum[a...b]
  end
end
# verification-helper: PROBLEM https://judge.yosupo.jp/problem/point_add_range_sum

# require "../../src/nglib/data_structure/dynamic_range_sum"
module NgLib
  # 動的な数列 $a$ に対して累積和を求めます。
  #
  # 累積和クエリは $O(\log{N})$ で処理することができます。
  #
  # 実装は BIT (Fenwick Tree) です。
  #
  # もし、区間加算 $1$ 点取得がしたい場合は、このライブラリといもす法を組み合わせると良いです。
  # 長さ $n$ の数列に対して操作する場合、BIT の長さは $n + 1$ 必要なことに注意してください。
  # - $[l, r)$ に $x$ を加算 : `#add(l, x); add(r, -x)`
  # - $i$ 番目を取得 : `#[..i]`
  class DynamicRangeSum(T)
    getter size : Int32
    @data : Array(T)

    # 長さが $n$ で各要素が $0$ の数列 $a$ を構築します。
    def initialize(n : Int)
      @data = Array(T).new(n) { T.zero }
      @size = @data.size
    end

    # 長さが $n$ で各要素が $val$ の数列 $a$ を構築します。
    def initialize(n : Int, val : T)
      @data = Array(T).new(n) { val }
      @size = @data.size
    end

    # 長さが $n$ で $i$ 番目の要素が $elems_i$ の数列 $a$ を構築します。
    def initialize(elems : Enumerable(T))
      @size = elems.size.to_i32
      @data = Array(T).new(@size, T.zero)
      elems.each_with_index { |x, i| add(i, x) }
    end

    # $[l, r)$ 番目までの要素の総和 $\sum_{i=l}^{r-1} a_i$ を $O(\log{N})$ で返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get(0, 5) # => 1 + 1 + 2 + 3 + 5 = 12
    # ```
    def get(l, r) : T
      raise IndexError.new("`l` and `r` must be 0 <= l <= r <= self.size (#{l}, #{r})") unless 0 <= l && l <= r && r <= @size
      sum(r) - sum(l)
    end

    # $[l, r)$ 番目までの要素の総和 $\sum_{i=l}^{r-1} a_i$ を $O(\log{N})$ で返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum[0, 5] # => 1 + 1 + 2 + 3 + 5 = 12
    # ```
    def [](l, r) : T
      get(l, r)
    end

    # `range` の表す範囲の要素の総和 $\sum_{i \in range} a_i$ を $O(\log{N})$ で返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get(0...5) # => 1 + 1 + 2 + 3 + 5 = 12
    # ```
    def get(range : Range(Int?, Int?)) : T
      l = (range.begin || 0)
      r = (range.end || @size) + (range.exclusive? || range.end.nil? ? 0 : 1)
      get(l, r)
    end

    # `range` の表す範囲の要素の総和 $\sum_{i \in range} a_i$ を $O(\log{N})$ で返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum[0...5] # => 1 + 1 + 2 + 3 + 5 = 12
    # ```
    def [](range : Range(Int?, Int?)) : T
      l = (range.begin || 0)
      r = (range.end || @size) + (range.exclusive? || range.end.nil? ? 0 : 1)
      get(l, r)
    end

    # $[l, r)$ 番目までの要素の総和 $\sum_{i=l}^{r-1} a_i$ を $O(\log{N})$ で返します。
    #
    # $0 \leq l \leq r \leq n$ を満たさないとき、`nil` を返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get?(0, 5) # => 1 + 1 + 2 + 3 + 5 = 12
    # csum.get?(7, 3) # => nil
    # ```
    def get?(l, r) : T?
      return nil unless 0 <= l && l <= r && r <= @size
      get(l, r)
    end

    # $[l, r)$ 番目までの要素の総和 $\sum_{i=l}^{r-1} a_i$ を $O(\log{N})$ で返します。
    #
    # $0 \leq l \leq r \leq n$ を満たさないとき、`nil` を返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum[0, 5]? # => 1 + 1 + 2 + 3 + 5 = 12
    # csum[7, 3]? # => nil
    # ```
    def []?(l, r) : T?
      get?(l, r)
    end

    # `range` の表す範囲の要素の総和 $\sum_{i \in range} a_i$ を $O(\log{N})$ で返します。
    #
    # $0 \leq l \leq r \leq n$ を満たさないとき、`nil` を返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get?(0...5) # => 1 + 1 + 2 + 3 + 5 = 12
    # csum.get?(7...3) # => nil
    # ```
    def get?(range : Range(Int?, Int?)) : T
      l = (range.begin || 0)
      r = (range.end || @size) + (range.exclusive? || range.end.nil? ? 0 : 1)
      get?(l, r)
    end

    # `range` の表す範囲の要素の総和 $\sum_{i \in range} a_i$ を $O(\log{N})$ で返します。
    #
    # $0 \leq l \leq r \leq n$ を満たさないとき、`nil` を返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum[0...5]? # => 1 + 1 + 2 + 3 + 5 = 12
    # csum[7...3]? # => nil
    # ```
    def []?(range : Range(Int?, Int?)) : T
      l = (range.begin || 0)
      r = (range.end || @size) + (range.exclusive? || range.end.nil? ? 0 : 1)
      get?(l, r)
    end

    # $a_i$ を $O(\log{N})$ で返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get(5) # => 8
    # ```
    def get(i) : T
      get(i, i + 1)
    end

    # $a_i$ を $O(\log{N})$ で返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum[5] # => 8
    # ```
    def [](i) : T
      get(i, i + 1)
    end

    # $a_i$ を $O(\log{N})$ で返します。
    #
    # $0 \leq i \lt n$ を満たさないとき、`nil` を返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get?(5) # => 8
    # csum.get?(10)? # => nil
    # ```
    def get?(i) : T?
      get?(i, i + 1)
    end

    # $a_i$ を $O(\log{N})$ で返します。
    #
    # $0 \leq i \lt n$ を満たさないとき、`nil` を返します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum[5]   # => 8
    # csum[10]? # => nil
    # ```
    def []?(i) : T?
      get?(i, i + 1)
    end

    # $a_i$ の値を $x$ に更新します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get?(0...5) # => 1 + 1 + 2 + 3 + 5 = 12
    # csum[0] = 100
    # csum.get?(0...5) # => 100 + 1 + 2 + 3 + 5 = 111
    # ```
    def []=(i : Int, x : T) : T
      add(i, x - get(i))
    end

    # $a_i$ の値を $x$ に更新します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get?(0...5) # => 1 + 1 + 2 + 3 + 5 = 12
    # csum.set(0, 100)
    # csum.get?(0...5) # => 100 + 1 + 2 + 3 + 5 = 111
    # ```
    def set(i : Int, x : T)
      self[i] = x
    end

    # $a_i$ に $x$ を加算します。
    #
    # ```
    # array = [1, 1, 2, 3, 5, 8, 13]
    # csum = DynamicRangeSum(Int32).new(array)
    # csum.get?(0...5) # => 1 + 1 + 2 + 3 + 5 = 12
    # csum.add(0, 99)
    # csum.get?(0...5) # => 100 + 1 + 2 + 3 + 5 = 111
    # ```
    def add(i : Int, x : T)
      i += 1
      while i <= @size
        @data[i - 1] += x
        i += i & -i
      end
      x
    end

    private def sum(r : Int) : T
      s = T.zero
      while r > 0
        s += @data[r - 1]
        r -= r & -r
      end
      s
    end
  end
end

_n, q = read_line.split.map &.to_i64
a = read_line.split.map &.to_i64

csum = NgLib::DynamicRangeSum(Int64).new(a)

q.times do
  t, a, b = read_line.split.map &.to_i64
  case t
  when 0
    csum.add(a, b)
  when 1
    puts csum[a...b]
  end
end
Back to top page