Description
给定 $n\ (1 \leq n \leq 10^5)$ 个数 $a_i\ (0 \leq a_i \leq 10^6)$,现在有 $m\ (1 \leq m \leq 5 \times 10^4)$ 个操作(操作有 $2$ 种):
1 l r
:求 $\sum\limits_{i=l}^{r}a_i\ (1 \leq l \leq r \leq n)$;
2 l r x
:区间 $[l,r]\ (1 \leq l \leq r \leq n)$ 内的数对 $x\ (1 \leq x \leq 10^6)$ 异或。
Source
Solution
前置知识:
线段树
因为是区间修改和区间查询,且异或具有结合律:$(a \oplus b) \oplus c = a \oplus (b \oplus c)$,我们很容易想到用线段树来维护。可是似乎打不了懒标记,怎么办?先考虑 $a_i$ 只有 $0$ 和 $1$ 两个值的情况,当对一条线段区间反转的时候,我们只需要让这条线段的懒标记异或 $1$,这个区间 $1$ 的个数变为 区间长度 - 原来区间 $1$ 的个数。标记下放时,如果这条线段的懒标记为 $1$,则将这条线段的左右区间反转(做上述反转操作),并清空这条线段的懒标记。
显然只有 $0$ 和 $1$ 时用线段树维护很简单,现在我们需要让这些数转化为 $0$ 和 $1$ 进行操作,这不就是把它们转化成 二进制 吗?相当于建了 $\log \max\begin{Bmatrix}a_i\end{Bmatrix}$ 棵线段树,分别维护 $a_i$ 在二进制下的每一位,以及每一位的区间和。对于即将异或的数 $x$,先找到要修改的区间 $[l,r]$,再把 $x$ 二进制拆分,如果 $x$ 在二进制下某一位是 $1$,我们就对这一位所在的线段树区间 $[l,r]$ 反转。查询时,同样先找到要查询的区间 $[l,r]$,把二进制下每一位所在的 线段树区间 $[l,r]$ 的和 × 二进制下这一位对应的值 加起来就是答案。因为每一次修改或查询都要在线段树内二进制拆分,所以时间复杂度为 $O(n\log^2n)$ 。
Code
1 |
|