使用二叉索引树(Fenwick树)求解范围最小查询

时间:2013-12-27 12:01:43

标签: algorithm tree fenwick-tree

正式地,范围最小查询问题是:

  

给定一个数组A [0,N-1],找到任意两个给定索引之间具有最小值的元素的位置。

现在,标准解决方案是使用分段树,并且已经描述了here。用于解决范围查询的另一个数据结构是二进制索引树(Fenwick树),它更容易理解和编码。

可以通过二进制索引树来解决范围最小查询问题,以及如何解决?将会感谢更新和查询功能的实现。

3 个答案:

答案 0 :(得分:5)

尽管有其他答案,但可以将Fenwick树用于任何范围的范围最小查询。我在这里发布了一个详细的解释:

How to adapt Fenwick tree to answer range minimum queries

简而言之,您需要维护

  • 表示节点[1,N]
  • 的实际值的数组
  • 以0为根的Fenwick树,其中任何节点i的父节点为i-(i&-i)
  • 以N + 1为根的Fenwick树,其中任何节点i的父节点为i+(i&-i)

查询O(log n)

中的任何范围
Query(int a, int b) {
  int val = infinity // always holds the known min value for our range

  // Start traversing the first tree, BIT1, from the beginning of range, a
  int i = a
  while (parentOf(i, BIT1) <= b) {
    val = min(val, BIT2[i]) // Note: traversing BIT1, yet looking up values in BIT2
    i = parentOf(i, BIT1)
  }

  // Start traversing the second tree, BIT2, from the end of range, b
  i = b
  while (parentOf(i, BIT2) >= a) {
    val = min(val, BIT1[i]) // Note: traversing BIT2, yet looking up values in BIT1
    i = parentOf(i, BIT2)
  }

  val = min(val, REAL[i])
  return val
}

要更新分摊的O(log n)中的任何值,您需要更新实际数组和两个树。更新单个树:

while (node <= n+1) {
  if (v > tree[node]) {
    if (oldValue == tree[node]) {
      v = min(v, real[node])
      for-each child {
        v = min(v, tree[child])
      }
    } else break
  }
  if (v == tree[node]) break
  tree[node] = v
  node = parentOf(node, tree)
}

答案 1 :(得分:2)

通常,可以针对任何可逆操作(例如加法,乘法)调整Fenwick树。

对于最小值,可以使用Fenwick树来回答0 ... x形式的间隔的查询(左点固定为0)。这是假设对位置x的更新操作仅降低存储值。

答案 2 :(得分:1)

我想知道同样的问题。但是,我认为fenwick树不可能执行最小/最大查询,这是因为它依赖于从a到b的累积频率为f(b)-f(a-1)的事实,属性对于最小/最大函数

无效