树状数组

树状数组是一种利用数的二进制特征进行检索的树状结构。

\(lowbit\) 函数:{\(lowbit(x) = x \& -x\)} 是 \(x\) 的二进制表示中最低的一位 \(1\),例如 \(x=(110)_{2},lowbit(x) = (10)_{2}\)

二进制特征:

对于任意两个数 \(x,y\),且 \(x<y\),它们的二进制表示中都存在唯一一个位置 \(pos\) 使得 \(x,y\) 在该位置上的表示分别是 \(0,1\),而该位置的左边部分表示完全相同。例如\((\overbrace{011}\underbrace{0}111001)_{2} < (\overbrace{011}\underbrace{1}011110)_{2}\),把样例中 \(pos\) 左边相同部分提取出来并令\(pos\)位置为\(1\),得到的新的二进制表示为\((0111000000)_{2}\),而 \(x,y\) 都可以通过 \(lowbit\)函数 得到新的二进制表示。

检索点:

上述中 \(y\) 想要检索 \(x\) 的信息,可以事先将 \(x\) 的信息存放在新的二进制表示中,再由 \(y\) 去检索新的二进制表示,所以新的二进制表示被称为检索点。

信息的存储:

由二进制特征可知,对任意位置 \(x\),可以不断调用 \(x = x + lowbit(x)\) 使得与任意 \(y\) 之间的检索点都能收到并存储 \(x\) 发出的信息。

信息的检索:

同样由二进制的特征可知,对于任意的 \(y\),可以不断调用 \(y = y - lowbit(y)\) 以接收所有 \(x\) 发出的信息。

树状结构:

根为 \(1\) 的二叉树,两个孩子结点依次是 \((i<<1), (i<<1|1)\),tree[] 用以存储结点信息,sum(r) 是求前 r 项和的函数。

由信息的存储可知,

\[\begin{cases} tree[(1000)_{2}] = sum((1000)_{2});\\ tree[(1100)_{2}] = sum((1100)_{2}) - sum((1000)_{2});\\ tree[(1110)_{2}] = sum((1110)_{2}) - sum((1100)_{2});\\ tree[(1111)_{2}] = sum((1111)_{2}) - sum((1110)_{2}); \end{cases} \]

由信息的检索可知,

\[sum((1111)_{2}) = tree[(1000)_{2}] + tree[(1100)_{2}] + tree[(1110)_{2}] + tree[(1111)_{2}] \\ \]

所以在 sum(r) = val 中(各项均为非负),已知 val,也可以反推出 r。

\[from \quad m\quad to\quad 0:\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\\ if\quad tree[x + 2^{i}] < val:\quad\quad\quad\quad\\ \begin{cases} val = val - tree[x + 2^{i}]\\ x = x + 2^{i} \end{cases}\\ \]

其中 \(m = 1<<(31-\_\_builtin\_clz(n))\) 是二进制表示的最高的一位 \(1\),而 \(r = x + 1\)

posted @ 2020-11-25 10:39  Daowuu  阅读(90)  评论(0编辑  收藏  举报