Arrays 查询数组中索引范围i,j中范围A[i],A[j]内的值

Arrays 查询数组中索引范围i,j中范围A[i],A[j]内的值,arrays,algorithm,count,Arrays,Algorithm,Count,假设我们有一个n个元素的数组(未排序)。给定一个带有两个参数i和j的查询,其中i和j是数组的索引,我想返回值x的数量。x在a[i]范围内,a[j](独占),x本身在索引范围i内,它可以通过Fenwick树来求解。首先,我们假设所有整数都小于10^6 阻止您直接使用Fenwick的问题是:如果您的查询是在完成Fenwick的树设置之后进行的,那么查询(a[i],a[j])将涉及一些要计数的数字a[k]。解决此问题的一个方法是根据右侧对查询进行排序,并在完成A[j]的芬威克更新后立即使用正确的索引j

假设我们有一个n个元素的数组(未排序)。给定一个带有两个参数i和j的查询,其中i和j是数组的索引,我想返回值x的数量。x在
a[i]范围内,a[j]
(独占),x本身在索引范围
i内,它可以通过Fenwick树来求解。首先,我们假设所有整数都小于10^6

阻止您直接使用Fenwick的问题是:如果您的查询是在完成Fenwick的树设置之后进行的,那么查询(
a[i]
a[j]
)将涉及一些要计数的数字
a[k]
。解决此问题的一个方法是根据右侧对查询进行排序,并在完成
A[j]
的芬威克更新后立即使用正确的索引
j
完成所有查询。这将确保来自后面索引的数字不会影响前面的计数

如果所有数字都在整数范围内,请将它们向下映射到
[1..N]
,其中
N
是启动上述例程之前数组的大小


总体复杂性将是
O(Q log Q+Q log N)
,其中
Q
是查询的数量,
N
是数组的大小。

可以通过使用与合并排序相关的段树来解决这个问题。在与范围[l,r]对应的每个节点上,存储在该节点中的数组将是[l…r]的排序数组。我们可以在O(n logn)时间内对其进行预处理,空间复杂度也将是O(n logn),因为每个元素在树的每个高度只出现一次,这等于O(logn)

构建此树的简单方法是使用O(nlogn)算法对每个节点上的数组进行排序,该算法的总时间复杂度为O(nlog^2n)。但是我已经提到,这个过程看起来像合并排序,所以我们可以使用相同的过程来获得O(n logn)构建时间的时间复杂度

例如,让我们考虑一下示例数组的前四个元素[ 3, 6, 7,1 ]。我描述的树将如下所示:

    [1,3,6,7]
       /    \ 
  [3,6]     [1,7]
   / \       / \
 [3]  [6]  [7] [1]
现在,如果对相应节点上的元素进行二进制搜索,查询可以在O(log^2 n)时间内完成

构建时间:O(n日志n)

查询时间:O(日志^2 n)

< >编辑(C++中的树的构造代码,查询作为练习):< /P>
#包括
使用名称空间std;
const int MAX_N=10000;
int A[MAX_N],N;//整数数组
向量T[MAX_N*4];
无效合并(向量与C、向量与A、向量与B){
int i=0,j=0,n=A.size(),m=B.size();
C.分配(n+m,0);
而(i如果(A[i]预处理的预期运行时间是多少?以及
A[i]
的范围是多少?i=2,j=4(A[i]=6,A[j]=1)的结果是0?@amit-year结果是0。因为7不在范围(6,1)内。@nevets数组的任何元素都在整数范围内。所以我预期预处理是O(nlogn)是的,这听起来很合理,也不难实现。但是在(a[i],a[j])范围内的值a[k]呢?kyou需要减去它们,即
Fenwick_Sum(a[j])-Fenwick_Sum(a[i]-1)
。这是一个很好的解决方案。您可以将查询时间缩短到O(logn)使用分数级联。谢谢。在查询中我没有得到的一件事是,(从示例开始),节点将对应于具有特定索引的排序数组。在示例中,1-4、1-2 3-4、1-1 2-2 3-3 4-4。因此,如果查询是2-4,我不知道该怎么办,因为没有直接对应的节点。我们将在节点2-2和3-4执行查询,并将结果相加。最多有日志(n)这样的节点我们必须进行二进制搜索,因此时间复杂度为O(log^2(n))。显然,分数级联可以加快速度,但我还没有检查出来。好的,谢谢,我将尝试O(log^2(n))先来看看。也许会是这样enough@user78451分数级级联的常数并不美妙;如果有的话,我不会期望有太多的加速。
6,7,4
    [1,3,6,7]
       /    \ 
  [3,6]     [1,7]
   / \       / \
 [3]  [6]  [7] [1]
#include <vector>
using namespace std;
const int MAX_N = 10000;

int A[MAX_N], N; // the array of the integers
vector<int> T[MAX_N * 4];

void merge(vector<int>& C, vector<int>& A, vector<int>& B){
  int i = 0, j = 0, n = A.size(), m = B.size();
  C.assign(n + m, 0);
  while(i < n || j < m){
    if(i == n) C[i + j] = B[j], j++;
    else if(j == m) C[i + j] = A[i], i++;
    else {
      if(A[i] <= B[j]) {
        C[i + j] = A[i];
        i++;
      } else {
        C[i + j] = B[j];
        j ++;
      }
    }
  }
}

void build(int n, int L, int R){
  if(L == R) T[n] = vector<int>(1, A[L]);
  else {
    build(n * 2, L, (L + R) / 2);
    build(n * 2 + 1, (L + R) / 2 + 1, R);
    merge(T[n], T[n * 2], T[n * 2 + 1]);
  }
}

int main(){
  N = 4;
  A[0] = 3, A[1] = 6, A[2] = 7, A[3] = 1;
  build(1, 0, N - 1);
  return 0;
}