空の配列があるとしましょう:
0 0 0 0 0 0 0 0 0 0 (array)
0 0 0 0 0 0 0 0 0 0 (cumulative sums)
そして、あなたは+5から[3..7]までの範囲の更新をしたいと思った:
0 0 0 5 5 5 5 5 0 0 (array)
0 0 0 5 10 15 20 25 25 25 (desired cumulative sums)
2つのバイナリインデックス付きツリーを使用して、目的の累積合計をどのように格納できますか?
トリックは、2つのバイナリインデックス付きツリー、BIT1とBIT2を使用することです。この場合、累積合計はそれらのコンテンツから計算されます。この例では、2つのツリーに次のものを格納します。
0 0 0 5 5 5 5 5 0 0 (BIT1)
0 0 0 10 10 10 10 10 -25 -25 (BIT2)
を見つけるsum[i]
には、これを計算します。
sum[i] = BIT1[i] * i - BIT2[i]
例えば:
sum[2] = 0*2 - 0 = 0
sum[3] = 5*3 - 10 = 5
sum[4] = 5*4 - 10 = 10
...
sum[7] = 5*7 - 10 = 25
sum[8] = 0*8 - (-25) = 25
sum[9] = 0*9 - (-25) = 25
以前の範囲の更新で目的のBIT1およびBIT2の値を達成するために、3つの範囲の更新を行います。
BIT1のインデックス3..7に対して+5の範囲の更新を行う必要があります。
BIT2のインデックス3..7に対して+10の範囲の更新を行う必要があります。
BIT2のインデックス8..9に対して-25の範囲の更新を行う必要があります。
次に、もう1つ変換を行います。上記のBIT1とBIT2の値を保存する代わりに、実際にはそれらの累積合計を保存します。これにより、累積合計に4つの更新を行うことにより、上記の3つの範囲の更新を行うことができます。
BIT1sum[3] += 5
BIT1sum[8] -= 5
BIT2sum[3] += 10
BIT2sum[8] -= 35
一般に、値vをrange [i..j]に追加するアルゴリズムは次のようになります。
BIT1sum[i] += v
BIT1sum[j+1] -= v
BIT2sum[i] += v * (i-1)
BIT2sum[j+1] -= v * j
ここで、+ =および-=構文は、BIT累積合計データ構造をそのインデックスの正または負の値で更新することを意味します。インデックスでBIT累積合計を更新すると、そのインデックスの右側にあるすべてのインデックスに暗黙的に影響することに注意してください。例えば:
0 0 0 0 0 0 0 0 0 0 (original)
BITsum[3] += 5
0 0 0 5 5 5 5 5 5 5 (after updating [3])
BITsum[8] -= 5
0 0 0 5 5 5 5 5 0 0 (after updating [8])
フェンウィックツリーは、合計をバイナリツリーに格納します。上記の更新を時間でフェンウィックツリーに行うのは簡単です。O (ログn )
sum[i] = BIT1[i] * i - BIT2[i]
か?それは動作するようですが、それはとても恣意的です...これに来るのにどのような洞察が可能ですか?