树状数组
树状数组是一种利用数的二进制特征进行检索的树状结构。
\(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}\\
\]