RMQ 問題は次のように拡張できます。
n
整数の配列が与えられますA
。
query(x, y): 2 つの整数 1 ≤ x
, y
≤が与えられn
た場合、 の最小値を見つけますA[x], A[x+1], ... A[y]
。
update(x, v):与えられた整数v
と 1 ≤ x
≤ n
do A[x] = v
.
この問題は、セグメント ツリーO(log n)
を使用する両方の操作で解決できます。
これは紙の上では効率的な解決策ですが、実際には、特に再帰的に実装する場合、セグメント ツリーには多くのオーバーヘッドが伴います。
O(log^2 n)
バイナリインデックスツリーを使用して、操作の1つ(または両方、よくわかりません)の問題を解決する方法があることを私は知っています(より多くのリソースが見つかりますが、これとこれはIMOです。それぞれ最も簡潔で網羅的です)。このソリューションは、 の値がn
メモリに収まるため、BIT のオーバーヘッドがはるかに少ないため、実際には高速です。
ただし、特定の操作を実行するために BIT 構造がどのように使用されるかはわかりません。たとえば、間隔の合計を照会するためにそれを使用する方法しか知りません。最小値を見つけるためにどのように使用できますか?
それが役立つ場合、私が求めていることを実行する他の人が書いたコードがありますが、それを理解することはできません. そのようなコードの 1 つを次に示します。
int que( int l, int r ) {
int p, q, m = 0;
for( p=r-(r&-r); l<=r; r=p, p-=p&-p ) {
q = ( p+1 >= l ) ? T[r] : (p=r-1) + 1;
if( a[m] < a[q] )
m = q;
}
return m;
}
void upd( int x ) {
int y, z;
for( y = x; x <= N; x += x & -x )
if( T[x] == y ) {
z = que( x-(x&-x) + 1, x-1 );
T[x] = (a[z] > a[x]) ? z : x;
}
else
if( a[ T[x] ] < a[ y ] )
T[x] = y;
}
上記のコードでT
は、 は 0 で初期化されa
、指定された配列とN
そのサイズ (何らかの理由で 1 からのインデックス付けを行います) でありupd
、すべての読み取り値に対して最初に呼び出されます。upd
呼び出される前にa[x] = v
実行されます。
また、p & -p
は一部の BIT ソースの と同じでありp ^ (p & (p - 1))
、インデックスは 1 から始まり、ゼロ要素が無限大に初期化されます。
上記がどのように機能するか、またはBITで特定の問題を解決する方法を誰かが説明できますか?