「HEOI2015」公约数数列
题目描述
设计一个数据结构. 给定一个正整数数列 $a_0, a_1, \ldots , a_{n - 1}$,你需要支持以下两种操作:
MODIFY id x
: 将 $a_{\text{id}}$ 修改为 $x$.QUERY x
: 求最小的整数 $p$ ($0 \leq p < n$),使得 $\text{gcd}(a_0, a_1, …, a_p) \cdot \text{XOR}(a_0, a_1, …, a_p) = x$. 其中 $\text{XOR}(a_0, a_1, …, a_p)$ 代表 $a_0, a_1, \ldots , a_p$ 的异或和,$\text{gcd}$ 表示最大公约数。
输入格式
输入数据的第一行包含一个正整数 $n$。
接下来一行包含 $n$ 个正整数 $a_0, a_1, …, a_{n - 1}$。
之后一行包含一个正整数 $q$,表示询问的个数。
之后 $q$ 行,每行包含一个询问。格式如题目中所述。
输出格式
对于每个 QUERY
询问,在单独的一行中输出结果。如果不存在这样的 $p$,输出 no
.
数据范围与提示
对于 $100\%$ 的数据,$n \leq 100000, \ q \leq 10000, \ a_i \leq 10^9 (0 \leq i < n)$,QUERY x
中的 $x \leq 10^{18}$,MODIFY id x
中的 $0 \leq \text{id} < n, \ 1 \leq x \leq 10^9$。
首先觉得直接上数据结构很不好维护,多半是分块。
这道题由于是前缀$gcd$,所以不同的$gcd$是$O(loga_0)$的(将$a_0$标准分解后考虑不难得知)。这提示我们可以枚举每个前缀$gcd$,在对应区间里查找是否有$x/gcd$的异或前缀和。如果没有修改操作,主席树可以轻松解决。有了修改操作就不那么好做了,下面考虑分块。
维护异或前缀和$sxor$。每个块里记录:块内所有数的$gcd$:$sgcd$,块的左右端点处的前缀$gcd$:$st,en$(整个$0$~$n-1$的区间),整体修改标记$lazy$,以及用unordered_map实现的Hash表,用于记录块内每个数的出现位置。
对于修改操作:异或前缀和部分,块内的$sxor$暴力修改,同时更新Hash表,之后整块修改$lazy$标记。$gcd$部分,通过暴力遍历得到整个块的$sgcd$,之后更新整块的$st$和$en$。
对于询问操作:按照块的左右顺序讨论。如果两块的左端点$st$值相等,那么说明这一块的前缀$gcd$都相等,此时直接在块里的Hash表查;否则暴力遍历查找。注意第一个判定是必要的——前面说明了不同的$gcd$只有$O(loga_0)$个,这里保证了询问操作的复杂度。
如果把求$gcd$和Hash表的复杂度视为常数,那么修改操作是$O(\sqrt n)$的,询问操作是$O(\sqrt nlogn)$的,可以通过本题。
1 |
|