RMQ 问题可以这样扩展:
给定的是一个n
整数数组A
。
query(x, y):给定两个整数 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)
一个(或两个,我不确定)操作中的问题,使用二进制索引树(可以找到更多资源,但是这个和这个是,IMO,分别是最简洁和详尽的)。n
对于适合内存的值,此解决方案在实践中更快,因为 BIT 的开销要少得多。
但是,我不知道如何使用 BIT 结构来执行给定的操作。例如,我只知道如何使用它来查询区间和。如何使用它找到最小值?
如果有帮助,我有其他人编写的代码可以满足我的要求,但我无法理解它。这是一段这样的代码:
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
被执行。
此外,与某些 BIT 源p & -p
中的 相同p ^ (p & (p - 1))
,索引从 1 开始,零元素初始化为无穷大。
谁能解释上述工作原理或我如何用 BIT 解决给定的问题?