LogoCSP Wiki By Yundou
3 DS

树状数组

引入

树状数组是一种支持 单点修改 和 区间查询 的,代码量小的数据结构。

什么是「单点修改」和「区间查询」?

假设有这样一道题:

已知一个数列 aa,你需要进行下面两种操作:

  • 给定 x,yx, y,将 a[x]a[x] 自增 yy。
  • 给定 l,rl, r,求解 a[l…r]a[l \ldots r] 的和。

其中第一种操作就是「单点修改」,第二种操作就是「区间查询」。

类似地,还有:「区间修改」、「单点查询」。它们分别的一个例子如下:

  • 区间修改:给定 l,r,xl, r, x,将 a[l…r]a[l \ldots r] 中的每个数都分别自增 xx;
  • 单点查询:给定 xx,求解 a[x]a[x] 的值。

注意到,区间问题一般严格强于单点问题,因为对单点的操作相当于对一个长度为 11 的区间操作。

普通树状数组维护的信息及运算要满足 结合律 且 可差分,如加法(和)、乘法(积)、异或等。

  • 结合律:(x∘y)∘z=x∘(y∘z)(x \circ y) \circ z = x \circ (y \circ z),其中 ∘\circ 是一个二元运算符。
  • 可差分:具有逆运算的运算,即已知 x∘yx \circ y 和 xx 可以求出 yy。

事实上,树状数组能解决的问题是线段树能解决的问题的子集:树状数组能做的,线段树一定能做;线段树能做的,树状数组不一定可以。然而,树状数组的代码要远比线段树短,时间效率常数也更小,因此仍有学习价值。

有时,在差分数组和辅助数组的帮助下,树状数组还可解决更强的 区间加单点值 和 区间加区间和 问题。

树状数组

初步感受

先来举个例子:我们想知道 a[1…7]a[1 \ldots 7] 的前缀和,怎么做?

一种做法是:a1+a2+a3+a4+a5+a6+a7a_1 + a_2 + a_3 + a_4 + a_5 + a_6 + a_7,需要求 77 个数的和。

但是如果已知三个数 AA,BB,CC,A=a[1…4]A = a[1 \ldots 4] 的和,B=a[5…6]B = a[5 \ldots 6] 的总和,C=a[7…7]C = a[7 \ldots 7] 的总和(其实就是 a[7]a[7] 自己)。你会怎么算?你一定会回答:A+B+CA + B + C,只需要求 33 个数的和。

这就是树状数组能快速求解信息的原因:我们总能将一段前缀 [1,n][1, n] 拆成 不多于 log⁡n\boldsymbol{\log n} 段区间,使得这 log⁡n\log n 段区间的信息是 已知的。

于是,我们只需合并这 log⁡n\log n 段区间的信息,就可以得到答案。相比于原来直接合并 nn 个信息,效率有了很大的提高。

不难发现信息必须满足结合律,否则就不能像上面这样合并了。

下面这张图展示了树状数组的工作原理:

示意图
示意图

最下面的八个方块代表原始数据数组 aa。上面参差不齐的方块(与最上面的八个方块是同一个数组)代表数组 aa 的上级——cc 数组。

cc 数组就是用来储存原始数组 aa 某段区间的和的,也就是说,这些区间的信息是已知的,我们的目标就是把查询前缀拆成这些小区间。

例如,从图中可以看出:

  • c2c_2 管辖的是 a[1…2]a[1 \ldots 2];
  • c4c_4 管辖的是 a[1…4]a[1 \ldots 4];
  • c6c_6 管辖的是 a[5…6]a[5 \ldots 6];
  • c8c_8 管辖的是 a[1…8]a[1 \ldots 8];
  • 剩下的 c[x]c[x] 管辖的都是 a[x]a[x] 自己(可以看做 a[x…x]a[x \ldots x] 的长度为 11 的小区间)。

不难发现,c[x]c[x] 管辖的一定是一段右边界是 xx 的区间总信息。我们先不关心左边界,先来感受一下树状数组是如何查询的。

举例:计算 a[1…7]a[1 \ldots 7] 的和。

过程:从 c7c_{7} 开始往前跳,发现 c7c_{7} 只管辖 a7a_{7} 这个元素;然后找 c6c_{6},发现 c6c_{6} 管辖的是 a[5…6]a[5 \ldots 6],然后跳到 c4c_{4},发现 c4c_{4} 管辖的是 a[1…4]a[1 \ldots 4] 这些元素,然后再试图跳到 c0c_0,但事实上 c0c_0 不存在,不跳了。

我们刚刚找到的 cc 是 c7,c6,c4c_7, c_6, c_4,事实上这就是 a[1…7]a[1 \ldots 7] 拆分出的三个小区间,合并得到答案是 c7+c6+c4c_7 + c_6 + c_4。

举例:计算 a[4…7]a[4 \ldots 7] 的和。

我们还是从 c7c_7 开始跳,跳到 c6c_6 再跳到 c4c_4。此时我们发现它管理了 a[1…4]a[1 \ldots 4] 的和,但是我们不想要 a[1…3]a[1 \ldots 3] 这一部分,怎么办呢?很简单,减去 a[1…3]a[1 \ldots 3] 的和就行了。

那不妨考虑最开始,就将查询 a[4…7]a[4 \ldots 7] 的和转化为查询 a[1…7]a[1 \ldots 7] 的和,以及查询 a[1…3]a[1 \ldots 3] 的和,最终将两个结果作差。

示意图
查询

管辖区间

那么问题来了,c[x](x≥1)c[x](x \ge 1) 管辖的区间到底往左延伸多少?也就是说,区间长度是多少?

树状数组中,规定 c[x]c[x] 管辖的区间长度为 2k2^{k},其中:

  • 设二进制最低位为第 00 位,则 kk 恰好为 xx 二进制表示中,最低位的 1 所在的二进制位数;
  • 2k2^k(c[x]c[x] 的管辖区间长度)恰好为 xx 二进制表示中,最低位的 1 以及后面所有 0 组成的数。

举个例子,c88c_{88} 管辖的是哪个区间?

因为 88(10)=01011000(2)88_{(10)}=01011000_{(2)},其二进制最低位的 1 以及后面的 0 组成的二进制是 1000,即 88,所以 c88c_{88} 管辖 88 个 aa 数组中的元素。

因此,c88c_{88} 代表 a[81…88]a[81 \ldots 88] 的区间信息。

我们记 xx 二进制最低位 1 以及后面的 0 组成的数为 lowbit⁡(x)\operatorname{lowbit}(x),那么 c[x]c[x] 管辖的区间就是 [x−lowbit⁡(x)+1,x][x-\operatorname{lowbit}(x)+1, x]。

这里注意:lowbit⁡\boldsymbol{\operatorname{lowbit}} 指的不是最低位 1 所在的位数 k\boldsymbol{k},而是这个 1 和后面所有 0 组成的 2k\boldsymbol{2^k}。

怎么计算 lowbit?根据位运算知识,可以得到 lowbit(x) = x & -x。

lowbit 的原理

将 x 的二进制所有位全部取反,再加 1,就可以得到 -x 的二进制编码。例如,66 的二进制编码是 110,全部取反后得到 001,加 1 得到 010。

设原先 x 的二进制编码是 (...)10...00,全部取反后得到 [...]01...11,加 1 后得到 [...]10...00,也就是 -x 的二进制编码了。这里 x 二进制表示中第一个 1 是 x 最低位的 1。

(...) 和 [...] 中省略号的每一位分别相反,所以 x & -x = (...)10...00 & [...]10...00 = 10...00,得到的结果就是 lowbit。

int lowbit(int x) {
  // x 的二进制中,最低位的 1 以及后面所有 0 组成的数。
  // lowbit(0b01011000) == 0b00001000
  //          ~~~~^~~~
  // lowbit(0b01110010) == 0b00000010
  //          ~~~~~~^~
  return x & -x;
}

区间查询

接下来我们来看树状数组具体的操作实现,先来看区间查询。

回顾查询 a[4…7]a[4 \ldots 7] 的过程,我们是将它转化为两个子过程:查询 a[1…7]a[1 \ldots 7] 和查询 a[1…3]a[1 \ldots 3] 的和,最终作差。

其实任何一个区间查询都可以这么做:查询 a[l…r]a[l \ldots r] 的和,就是 a[1…r]a[1 \ldots r] 的和减去 a[1…l−1]a[1 \ldots l - 1] 的和,从而把区间问题转化为前缀问题,更方便处理。

事实上,将有关 l…rl \ldots r 的区间询问转化为 1…r1 \ldots r 和 1…l−11 \ldots l - 1 的前缀询问再差分,在竞赛中是一个非常常用的技巧。

那前缀查询怎么做呢?回顾下查询 a[1…7]a[1 \ldots 7] 的过程:

从 c7c_{7} 往前跳,发现 c7c_{7} 只管辖 a7a_{7} 这个元素;然后找 c6c_{6},发现 c6c_{6} 管辖的是 a[5…6]a[5 \ldots 6],然后跳到 c4c_{4},发现 c4c_{4} 管辖的是 a[1…4]a[1 \ldots 4] 这些元素,然后再试图跳到 c0c_0,但事实上 c0c_0 不存在,不跳了。

我们刚刚找到的 cc 是 c7,c6,c4c_7, c_6, c_4,事实上这就是 a[1…7]a[1 \ldots 7] 拆分出的三个小区间,合并一下,答案是 c7+c6+c4c_7 + c_6 + c_4。

观察上面的过程,每次往前跳,一定是跳到现区间的左端点的左一位,作为新区间的右端点,这样才能将前缀不重不漏地拆分。比如现在 c6c_6 管的是 a[5…6]a[5 \ldots 6],下一次就跳到 5−1=45 - 1 = 4,即访问 c4c_4。

我们可以写出查询 a[1…x]a[1 \ldots x] 的过程:

  • 从 c[x]c[x] 开始往前跳,有 c[x]c[x] 管辖 a[x−lowbit⁡(x)+1…x]a[x-\operatorname{lowbit}(x)+1 \ldots x];
  • 令 x←x−lowbit⁡(x)x \gets x - \operatorname{lowbit}(x),如果 x=0x = 0 说明已经跳到尽头了,终止循环;否则回到第一步。
  • 将跳到的 cc 合并。

实现时,我们不一定要先把 cc 都跳出来然后一起合并,可以边跳边合并。

比如我们要维护的信息是和,直接令初始 ans=0\mathrm{ans} = 0,然后每跳到一个 c[x]c[x] 就 ans←ans+c[x]\mathrm{ans} \gets \mathrm{ans} + c[x],最终 ans\mathrm{ans} 就是所有合并的结果。

int getsum(int x) {  // a[1]..a[x] 的和
  int ans = 0;
  while (x > 0) {
    ans = ans + c[x];
    x = x - lowbit(x);
  }
  return ans;
}

树状数组与其树形态的性质

在讲解单点修改之前,先讲解树状数组的一些基本性质,以及其树形态来源,这有助于更好理解树状数组的单点修改。

我们约定:

  • l(x)=x−lowbit⁡(x)+1l(x) = x - \operatorname{lowbit}(x) + 1。即,l(x)l(x) 是 c[x]c[x] 管辖范围的左端点。
  • 对于任意正整数 xx,总能将 xx 表示成 s×2k+1+2ks \times 2^{k + 1} + 2^k 的形式,其中 lowbit⁡(x)=2k\operatorname{lowbit}(x) = 2^k。
  • 下面「c[x]c[x] 和 c[y]c[y] 不交」指 c[x]c[x] 的管辖范围和 c[y]c[y] 的管辖范围不相交,即 [l(x),x][l(x), x] 和 [l(y),y][l(y), y] 不相交。「c[x]c[x] 包含于 c[y]c[y]」等表述同理。

性质 1\boldsymbol{1}:对于 x≤y\boldsymbol{x \le y},要么有 c[x]\boldsymbol{c[x]} 和 c[y]\boldsymbol{c[y]} 不交,要么有 c[x]\boldsymbol{c[x]} 包含于 c[y]\boldsymbol{c[y]}。

证明

证明:假设 c[x]c[x] 和 c[y]c[y] 相交,即 [l(x),x][l(x), x] 和 [l(y),y][l(y), y] 相交,则一定有 l(y)≤x≤yl(y) \le x \le y。

将 yy 表示为 s×2k+1+2ks \times 2^{k +1} + 2^k,则 l(y)=s×2k+1+1l(y) = s \times 2^{k + 1} + 1。所以,xx 可以表示为 s×2k+1+bs \times 2^{k +1} + b,其中 1≤b≤2k1 \le b \le 2^k。

不难发现 lowbit⁡(x)=lowbit⁡(b)\operatorname{lowbit}(x) = \operatorname{lowbit}(b)。又因为 b−lowbit⁡(b)≥0b - \operatorname{lowbit}(b) \ge 0,

所以 l(x)=x−lowbit⁡(x)+1=s×2k+1+b−lowbit⁡(b)+1≥s×2k+1+1=l(y)l(x) = x - \operatorname{lowbit}(x) + 1 = s \times 2^{k +1} + b - \operatorname{lowbit}(b) +1 \ge s \times 2^{k +1} + 1 = l(y),即 l(y)≤l(x)≤x≤yl(y) \le l(x) \le x \le y。

所以,如果 c[x]c[x] 和 c[y]c[y] 相交,那么 c[x]c[x] 的管辖范围一定完全包含于 c[y]c[y]。

性质 2\boldsymbol{2}:c[x]\boldsymbol{c[x]} 真包含于 c[x+lowbit⁡(x)]\boldsymbol{c[x + \operatorname{lowbit}(x)]}。

证明

证明:设 y=x+lowbit⁡(x)y = x + \operatorname{lowbit}(x),x=s×2k+1+2kx = s \times 2^{k + 1} + 2^k,则 y=(s+1)×2k+1y = (s + 1) \times 2^{k +1},l(x)=s×2k+1+1l(x) = s \times 2^{k + 1} + 1。

不难发现 lowbit⁡(y)≥2k+1\operatorname{lowbit}(y) \ge 2^{k + 1},所以 l(y)=(s+1)×2k+1−lowbit⁡(y)+1≤s×2k+1+1=l(x)l(y) = (s + 1) \times 2^{k + 1} - \operatorname{lowbit}(y) + 1 \le s \times 2^{k +1} + 1= l(x),即 l(y)≤l(x)≤x<yl(y) \le l(x) \le x < y。

所以,c[x]c[x] 真包含于 c[x+lowbit⁡(x)]c[x + \operatorname{lowbit}(x)]。

性质 33:对于任意 x<y<x+lowbit⁡(x)\boldsymbol{x < y < x + \operatorname{lowbit}(x)},有 c[x]\boldsymbol{c[x]} 和 c[y]\boldsymbol{c[y]} 不交。

证明

证明:设 x=s×2k+1+2kx = s \times 2^{k + 1} + 2^k,则 y=x+b=s×2k+1+2k+by = x + b = s \times 2^{k + 1} + 2^k + b,其中 1≤b<2k1 \le b < 2^k。

不难发现 lowbit⁡(y)=lowbit⁡(b)\operatorname{lowbit}(y) = \operatorname{lowbit}(b)。又因为 b−lowbit⁡(b)≥0b - \operatorname{lowbit}(b) \ge 0,

因此 l(y)=y−lowbit⁡(y)+1=x+b−lowbit⁡(b)+1>xl(y) = y - \operatorname{lowbit}(y) + 1 = x + b - \operatorname{lowbit}(b) + 1 > x,即 l(x)≤x<l(y)≤yl(x) \le x < l(y) \le y。

所以,c[x]c[x] 和 c[y]c[y] 不交。

有了这三条性质的铺垫,我们接下来看树状数组的树形态(请忽略 aa 向 cc 的连边)。

示意图
图示

事实上,树状数组的树形态是 xx 向 x+lowbit⁡(x)x + \operatorname{lowbit}(x) 连边得到的图,其中 x+lowbit⁡(x)x + \operatorname{lowbit}(x) 是 xx 的父亲。

注意,在考虑树状数组的树形态时,我们不考虑树状数组大小的影响,即我们认为这是一棵无限大的树,方便分析。实际实现时,我们只需用到 x≤nx \le n 的 c[x]c[x],其中 nn 是原数组长度。

这棵树天然满足了很多美好性质,下面列举若干(设 fa[u]fa[u] 表示 uu 的直系父亲):

  • u<fa[u]u < fa[u]。
  • uu 大于任何一个 uu 的后代,小于任何一个 uu 的祖先。
  • 点 uu 的 lowbit⁡\operatorname{lowbit} 严格小于 fa[u]fa[u] 的 lowbit⁡\operatorname{lowbit}。

证明

设 y=x+lowbit⁡(x)y = x + \operatorname{lowbit}(x),x=s×2k+1+2kx = s \times 2^{k + 1} + 2^k,则 y=(s+1)×2k+1y = (s + 1) \times 2^{k +1},不难发现 lowbit⁡(y)≥2k+1>lowbit⁡(x)\operatorname{lowbit}(y) \ge 2^{k + 1} > \operatorname{lowbit}(x),证毕。

  • 点 xx 的高度是 log⁡2lowbit⁡(x)\log_2\operatorname{lowbit}(x),即 xx 二进制最低位 1 的位数。

高度的定义

点 xx 的高度 h(x)h(x) 满足:如果 x mod 2=1x \bmod 2 = 1,则 h(x)=0h(x) = 0,否则 h(x)=max⁡(h(y))+1h(x) = \max(h(y)) + 1,其中 yy 代表 xx 的所有儿子(此时 xx 至少存在一个儿子 x−1x - 1)。

也就是说,一个点的高度恰好比它最高的那个儿子再高 11。如果一个点没有儿子,它的高度是 00。

这里引出高度这一概念,是为后面解释复杂度更方便。

  • c[u]c[u] 真包含于 c[fa[u]]c[fa[u]](性质 22)。
  • c[u]c[u] 真包含于 c[v]c[v],其中 vv 是 uu 的任一祖先(在上一条性质上归纳)。
  • c[u]c[u] 真包含 c[v]c[v],其中 vv 是 uu 的任一后代(上面那条性质 uu,vv 颠倒)。
  • 对于任意 v′>uv' > u,若 v′v' 不是 uu 的祖先,则 c[u]c[u] 和 c[v′]c[v'] 不交。

证明

uu 和 uu 的祖先中,一定存在一个点 vv 使得 v<v′<fa[v]v < v' < fa[v],根据性质 33 得 c[v′]c[v'] 不相交于 c[v]c[v],而 c[v]c[v] 包含 c[u]c[u],因此 c[v′]c[v'] 不交于 c[u]c[u]。

  • 对于任意 v<uv < u,如果 vv 不在 uu 的子树上,则 c[u]c[u] 和 c[v]c[v] 不交(上面那条性质 uu,v′v' 颠倒)。
  • 对于任意 v>uv > u,当且仅当 vv 是 uu 的祖先,c[u]c[u] 真包含于 c[v]c[v](上面几条性质的总结)。这就是树状数组单点修改的核心原理。
  • 设 u=s×2k+1+2ku = s \times 2^{k + 1} + 2^k,则其儿子数量为 k=log⁡2lowbit⁡(u)k = \log_2\operatorname{lowbit}(u),编号分别为 u−2t(0≤t<k)u - 2^t(0 \le t < k)。
    • 举例:假设 k=3k = 3,uu 的二进制编号为 ...1000,则 uu 有三个儿子,二进制编号分别为 ...0111、...0110、...0100。

证明

在一个数 xx 的基础上减去 2t2^t,xx 二进制第 tt 位会反转,而更低的位保持不变。

考虑 uu 的儿子 vv,有 v+lowbit⁡(v)=uv + \operatorname{lowbit}(v) = u,即 v=u−2tv = u - 2^t 且 lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t。设 u=s×2k+1+2ku = s \times 2^{k + 1} + 2^k。

考虑 0≤t<k\boldsymbol{0 \le t < k},uu 的第 tt 位及后方均为 00,所以 v=u−2tv = u - 2^t 的第 tt 位变为 11,后面仍为 00,满足 lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t。

考虑 t=k\boldsymbol{t = k},则 v=u−2kv = u - 2^k,vv 的第 kk 位变为 00,不满足 lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t。

考虑 t>k\boldsymbol{t > k},则 v=u−2tv = u - 2^t,vv 的第 kk 位是 11,所以 lowbit⁡(v)=2k\operatorname{lowbit}(v) = 2^k,不满足 lowbit⁡(v)=2t\operatorname{lowbit}(v) = 2^t。

  • uu 的所有儿子对应 cc 的管辖区间恰好拼接成 [l(u),u−1][l(u), u - 1]。
    • 举例:假设 k=3k = 3,uu 的二进制编号为 ...1000,则 uu 有三个儿子,二进制编号分别为 ...0111、...0110、...0100。
    • c[...0100] 表示 a[...0001 ~ ...0100]。
    • c[...0110] 表示 a[...0101 ~ ...0110]。
    • c[...0111] 表示 a[...0111 ~ ...0111]。
    • 不难发现上面是三个管辖区间的并集恰好是 a[...0001 ~ ...0111],即 [l(u),u−1][l(u), u - 1]。

证明

uu 的儿子总能表示成 u−2t(0≤t<k)u - 2^t(0 \le t < k),不难发现,tt 越小,u−2tu - 2^t 越大,代表的区间越靠右。我们设 f(t)=u−2tf(t) = u - 2^t,则 f(k−1),f(k−2),…,f(0)f(k - 1), f(k - 2), \ldots, f(0) 分别构成 uu 从左到右的儿子。

不难发现 lowbit⁡(f(t))=2t\operatorname{lowbit}(f(t)) = 2^t,所以 l(f(t))=u−2t−2t+1=u−2t+1+1l(f(t)) = u - 2^t - 2^t + 1 = u - 2^{t + 1} + 1。

考虑相邻的两个儿子 f(t+1)f(t + 1) 和 f(t)f(t)。前者管辖区间的右端点是 f(t+1)=u−2t+1f(t + 1) = u - 2^{t + 1},后者管辖区间的左端点是 l(f(t))=u−2t+1+1l(f(t)) = u - 2^{t + 1} + 1,恰好相接。

考虑最左面的儿子 f(k−1)f(k - 1),其管辖左边界 l(f(k−1))=u−2k+1l(f(k - 1)) = u - 2^k + 1 恰为 l(u)l(u)。

考虑最右面的儿子 f(0)f(0),其管辖右边界就是 u−1u - 1。

因此,这些儿子的管辖区间可以恰好拼成 [l(u),u−1][l(u), u - 1]。

单点修改

现在来考虑如何单点修改 a[x]a[x]。

我们的目标是快速正确地维护 cc 数组。为保证效率,我们只需遍历并修改管辖了 a[x]a[x] 的所有 c[y]c[y],因为其他的 cc 显然没有发生变化。

管辖 a[x]a[x] 的 c[y]c[y] 一定包含 c[x]c[x](根据性质 11),所以 yy 在树状数组树形态上是 xx 的祖先。因此我们从 xx 开始不断跳父亲,直到跳得超过了原数组长度为止。

设 nn 表示 aa 的大小,不难写出单点修改 a[x]a[x] 的过程:

  • 初始令 x′=xx' = x。
  • 修改 c[x′]c[x']。
  • 令 x′←x′+lowbit⁡(x′)x' \gets x' + \operatorname{lowbit}(x'),如果 x′>nx' > n 说明已经跳到尽头了,终止循环;否则回到第二步。

区间信息和单点修改的种类,共同决定 c[x′]c[x'] 的修改方式。下面给几个例子:

  • 若 c[x′]c[x'] 维护区间和,修改种类是将 a[x]a[x] 加上 pp,则修改方式则是将所有 c[x′]c[x'] 也加上 pp。
  • 若 c[x′]c[x'] 维护区间积,修改种类是将 a[x]a[x] 乘上 pp,则修改方式则是将所有 c[x′]c[x'] 也乘上 pp。

然而,单点修改的自由性使得修改的种类和维护的信息不一定是同种运算,比如,若 c[x′]c[x'] 维护区间和,修改种类是将 a[x]a[x] 赋值为 pp,可以考虑转化为将 a[x]a[x] 加上 p−a[x]p - a[x]。如果是将 a[x]a[x] 乘上 pp,就考虑转化为 a[x]a[x] 加上 a[x]×p−a[x]a[x] \times p - a[x]。

下面以维护区间和,单点加为例给出实现。

void add(int x, int k) {
  while (x <= n) {  // 不能越界
    c[x] = c[x] + k;
    x = x + lowbit(x);
  }
}

建树

也就是根据最开始给出的序列,将树状数组建出来(cc 全部预处理好)。

一般可以直接转化为 nn 次单点修改,时间复杂度 Θ(nlog⁡n)\Theta(n \log n)(复杂度分析在后面)。

比如给定序列 a=(5,1,4)a = (5, 1, 4) 要求建树,直接看作对 a[1]a[1] 单点加 55,对 a[2]a[2] 单点加 11,对 a[3]a[3] 单点加 44 即可。

复杂度分析

空间复杂度显然 Θ(n)\Theta(n)。

时间复杂度:

  • 对于区间查询操作:整个 x←x−lowbit⁡(x)x \gets x - \operatorname{lowbit}(x) 的迭代过程,可看做将 xx 二进制中的所有 11,从低位到高位逐渐改成 00 的过程,拆分出的区间数等于 xx 二进制中 11 的数量(即 popcount⁡(x)\operatorname{popcount}(x))。因此,单次查询时间复杂度是 Θ(log⁡n)\Theta(\log n);
  • 对于单点修改操作:跳父亲时,访问到的高度一直严格增加,且始终有 x≤nx \le n。由于点 xx 的高度是 log⁡2lowbit⁡(x)\log_2\operatorname{lowbit}(x),所以跳到的高度不会超过 log⁡2n\log_2n,所以访问到的 cc 的数量是 log⁡n\log n 级别。因此,单次单点修改复杂度是 Θ(log⁡n)\Theta(\log n)。

例题: