【競プロ】いもす法
いもす法は、配列に対して特定の区間を増減した結果を高速で求めるアルゴリズム
雰囲気
配列のある区間に値
- 区間の初めに
、区間の終わりに+\alpha しておく-\alpha
区間の初めに 、区間の終わりに+\beta しておく-\beta
... - あとで累積和を求める
とすることで、毎回区間に値を足すよりも高速に配列の値を求められる
例
例えば、長さ6の配列arr
が以下のように与えられたとする
[0 0 0 0 0 0]
区間[1, 3]
に+2
を行い、その後区間[2, 5]
に+3
を行うとする
いもす法を用いて解く
最初に区間[1, 3]
に+2
を行うため、arr[1]
を+2
してarr[4]
を-2
する
[0 2 0 0 -2 0]
次に区間[2, 5]
に+3
を行うため、arr[2]
を+3
する(arr[6]
は範囲外なので-3
しなくていい)
[0 2 3 0 -2 0]
最後に累積和(arr
を左から累積した値)を求める
[0 2 5 5 3 3]
ちゃんと区間[1, 3], [2, 5]
の共通部分[2, 3]
が2+3=5
になっている!
アルゴリズム
クエリが
- 各
に対し、t\in [Q] をA_{i_t} 、+\alpha_t をA_{j_t} する-\alpha_t - 配列
の累積和A を求めるS S_0=A_0, S_i=S_{i-1}+A_i
1. は
記法について
高次元版
簡単のため、2次元とする
クエリが
- 各
に対し、t\in [Q] をA_{i_t,k_l}, A_{j_t,l_l} 、+\alpha_t をA_{i_t,l_l}, A_{j_t,k_l} する-\alpha_t - 配列
の累積和A を求めるS S_{0,0}=A_{0,0}, S_{i,j}=\sum_{x\le i, y\le j} A_{x,y}
なぜこうなるのか
区間の増減に対して差分をとっていることに対応する
あとで累積和をとることで実際の値になる
証明
長さ
および
を考える
ここで、
とすると差分を取って、
差分について
ここで、数列
とする(ただし、
(1)に対して差分を取ると、
ここで、
特に、数列
これは、1. でもとめた配列に
(本来の証明と異なると思います)
参考
Discussion