「与えられた配列に対して,ある範囲についての大量のクエリを処理しろ」というときには以下のテクニックが有効.基本的には「大量のクエリ」を処理するために,$O(N)$ぐらいの前処理をしてクエリ自体には$O(1)$で答えられるようにするというのが基本戦略.
- 累積和
- Binary Index Tree
- Segment Tree
# 累積和
「累積和の差」が「範囲の和」になるということを利用.累積和の作り方は添字が煩雑になりやすいので,次のように作ると決めてしまうと楽.
長さNの整数配列arrの累積和accumは
accum[0]=0accum[i+1]=accum[i]+arr[i]
このとき,範囲[left, right)について
arr[left:right]=accum[right]-accum[left]

累積和
ここで意識すべきは,
accum[0]=0- 範囲は右開区間
- 問題上で範囲が与えられるときは左右閉区間で与えられることが多いので,その時は
accumにアクセスするタイミングで1足すなりして対応する
- 問題上で範囲が与えられるときは左右閉区間で与えられることが多いので,その時は
# 例題1
長さ$N$の整数列$A$があります.$A$の空でない連続する部分列であって,その総和が$0$になるものの個数を求めてください.ただし,ここで数えるのは部分列の取り出し方であることに注意してください.つまり,ある$2$つの部分列が列として同じでも,取り出した位置が異なるならば,それらは別々に数えるものとします.
from
https://atcoder.jp/contests/agc023/tasks/agc023_a
累積和をとって,集計する.
| |
# 例題2
Given an integer array
nums, handle multiple queries of the following type:Calculate the sum of the elements of
numsbetween indicesleftandrightinclusive whereleft<=right. Implement theNumArrayclass:
NumArray(int[] nums)Initializes the object with the integer arraynums.int sumRange(int left, int right)Returns the sum of the elements ofnumsbetween indicesleftandrightinclusive (i.e.nums[left] + nums[left + 1] + ... + nums[right]).from
https://leetcode.com/problems/range-sum-query-immutable/
まさしく累積和を使ってほしいという意図が見える問題.問題文中では範囲が閉区間で行われているので,それに合わせてsumRange内でrightの扱いに注意する.
| |
# 二次元累積和
ついでなので二次元配列の累積和についても記載しておく.
二次元配列Aが与えられたときに,[x1, x2) x [y1, y2)である長方形の範囲内の要素の総和を求めるクエリを考える.
累積和accumは
accum[0][0]=0accum[i][j]=[0, i)x[0, j)の長方形範囲の総和accum[i+1][j+1] = accum[i+1][j] + accum[i][j+1] - accum[i][j] + A[i][j]
こうすることで,[x1, x2) x [y1, y2)である長方形の範囲内の要素の総和は,accum[x2][y2] - accum[x1][y2] - accum[x2][y1] + accum[x1][y1]で求められる.
# 例題
Given a 2D matrix
matrix, handle multiple queries of the following type:Calculate the sum of the elements of
matrixinside the rectangle defined by its upper left corner(row1, col1)and lower right corner(row2, col2). Implement theNumMatrixclass:
NumMatrix(int[][] matrix)Initializes the object with the integer matrixmatrix.int sumRegion(int row1, int col1, int row2, int col2)Returns the sum of the elements ofmatrixinside the rectangle defined by its upper left corner(row1, col1)and lower right corner(row2, col2).from
https://leetcode.com/problems/range-sum-query-2d-immutable/
| |
# Segment Tree
配列を「区間」を単位に完全二分木で管理する.
1-indexな配列上に完全二分木を実装する.頂点iの子供は頂点2*i,頂点2*i + 1.

セグメント木は配列で実装する
updateクエリでは上にさかのぼっていきながら木を更新する.

`update`クエリ系
rangeクエリでは下から該当する範囲を拾っていくイメージ.

`range`クエリ系
なお,クエリ時のインデックスは0-indexであることに注意.
| |
# 例題
Given an integer array
nums, handle multiple queries of the following types:
- Update the value of an element in
nums.- Calculate the sum of the elements of
numsbetween indicesleftandrightinclusive whereleft<=right. Implement theNumArrayclass:
NumArray(int[] nums)Initializes the object with the integer arraynums.void update(int index, int val)Updates the value ofnums[index]to beval.int sumRange(int left, int right)Returns the sum of the elements ofnumsbetween indices left and right inclusive (i.e.nums[left] + nums[left + 1] + ... + nums[right]).from
https://leetcode.com/problems/range-sum-query-mutable/
要するにfunc=sumなセグメント木を実装しろという問題.
| |
# Binary Index Tree(BIT)
セグメント木から機能を削ぎ落とした感じ.

Binary Index Tree
- BITは
1-indexな配列上に作る updateクエリ- 次に更新すべきBIT上の位置は,現在見ている位置にその位置が相当する区間の長さを足すと出てくる
- BIT上の位置
posについて,posの担当する範囲の長さはpos & -posposのビット列の1が立ってる一番小さい桁を取ってる
rangeクエリ- BITに対する
rangeクエリは「[0, idx)の範囲の和」というクエリ- これを2つ組み合わせれば任意の範囲の和が取れる
[idx0, idx1)=[0, idx1)-[0, idx0)
- 次に足すべきBIT上の位置は,現在見ている位置にその位置が相当する区間の長さを引くと出てくる
- BITに対する
| |
# Refs
- https://qiita.com/drken/items/56a6b68edef8fc605821
- 累積和
- https://atcoder.jp/contests/agc023/tasks/agc023_a
- https://leetcode.com/problems/range-sum-query-immutable/
- https://leetcode.com/problems/range-sum-query-mutable/
- https://leetcode.com/problems/range-sum-query-2d-immutable/
- 🔒 https://leetcode.com/problems/range-sum-query-2d-mutable/
- https://www.slideshare.net/iwiwi/ss-3578491
- セグメント木
- https://qiita.com/takayg1/items/c811bd07c21923d7ec69
- セグメント木のPython実装
- http://hos.ac/slides/20140319_bit.pdf
- BIT
- https://ikatakos.com/pot/programming_algorithm/data_structure/binary_indexed_tree
- BIT