Range Queries

Instructions

在这一章,我们考虑一种能够维护区间询问(Range Queries)的数据结构。
在一个区间询问中,我们的目标是对数列的某个区间 [a,b][a,b] 得到一个固定的信息。

经典的区间查询:

  • sum⁡q(a,b)\operatorname{sum}_q(a,b):区间 [a,b][a,b] 的所有值的和;
  • min⁡q(a,b)\operatorname{min}_q(a,b):区间 [a,b][a,b] 中的最小值;
  • max⁡q(a,b)\operatorname{max}_q(a,b):区间 [a,b][a,b] 中的最大值。

几个例子,对于下面数列的区间 [3,6][3,6] 进行询问:

ii 00 11 22 33 44 55 66 77
aia_i 11 33 88 44 66 11 33 44

在这个例子中,sum⁡q(3,6)=14\operatorname{sum}_q(3,6)=14,min⁡q(3,6)=1\operatorname{min}_q(3,6)=1,max⁡q(3,6)=6\operatorname{max}_q(3,6)=6。

考虑暴力做法,以 sum 操作为例:

int sum(int a, int b) {
    int s = 0;
    for (int i = a; i <= b; ++i)
        s += array[i];
    return s;
}

非常简单,max 和 min 操作也是如此,应该不需要太多解释了吧。

若 nn 为数组长度,qq 为询问次数,则这段代码是最坏时间复杂度是 O(nq)O(nq) 的。

如果 nn 和 qq 都很大(均为 10510^5 级别),那么这段代码的效率会非常低。

Static array queries

静态区间查询,就是不进行修改的区间查询,对于序列某段的和,可以用前缀和很轻松地解决,这个就不必多说了。

首先,那么对于任意区间 [l,r][l,r] 和任意下标 idid,其中 1≤id≤l≤r≤n1\leq id\leq l\leq r\leq n,都有 sum⁡q(l,r)=sum⁡q(id,r)−sum⁡q(id,l−1)\operatorname{sum}_q(l,r)=\operatorname{sum}_q(id,r)-\operatorname{sum}_q(id,l-1)。
因此,大致思路就是令 qi=sum⁡q(1,i)q_i=\operatorname{sum}_q(1,i),那么 sum⁡q(l,r)=qr−ql−1\operatorname{sum}_q(l,r)=q_r-q_{l-1}。

int q[N],a[N];
void init(int n) {
    q[0]=0;
    for(int i=1;i<=n;++i) q[i]=q[i-1]+a[i];
}
int query(int l,int r) {
    return q[r]-q[l-1];
}

代码大致就是如此。

对于 max 和 min 操作,可以参照 st 表进行操作。

赞赏