随机化 + 分块维护 hash 表.
每个数出现奇数次有一个比较常用的处理方法,就给每个数随机分配一个较大的权值.
若区间内所有数权值异或和等于区间内所有出现过的数权值异或和,则说明每个数都出现了奇数次.
考虑枚举右端点 $r$ ,统计有几个左端点 $l$ 满足要求.
记 $p(x)$ 表示 $[x,r]$ 所有出现过的数权值异或和,在加入 $r$ 时给 $[lst(a_r)+1,r]$ 内的 $p$ 异或上 $a_r$ 的权值.
记前缀和 $s(x)$ 表示 $[1,x]$ 内所有数的异或和,在加入 $r$ 时只用计算出 $s(r)$ ,对前面的 $r$ 无影响.
若区间 $[l,r]$ 合法,则有 $p(l)=s(r)\oplus s(l-1)$ ,即 $p(l)\oplus s(l-1)=s(r)$ .
给每个 $l$ 维护出 $val(l)=p(l)\oplus s(l-1)$ ,修改时会给某个区间异或上一个 $v$ ,询问时询问内区间有几个 $v$ .
用分块 + hash 表维护,修改时整块打标记,边角暴力重构,询问时整块直接询问 hash 表,边角暴力重构后再询问.
时间复杂度 $O(n\sqrt n)$ .
有一个很有用的剪枝,询问时,若边角块没有标记,就可以不用重构.
1 | //%std |