学会从查询公式反推节点摘要,把多个可合并量组成乘积幺半群,并推导区间乘法对“乘积 + 质因子集合”的 Lazy 作用。
前置:Lazy Segment Tree、快速幂、Euler $φ$ 公式、位掩码。
线段树不是只能保存一个数。只要摘要能结合、修改能作用于摘要并可组合 Lazy,就能维护:
$$ summary=(product\bmod M,\ primeMask), $$
合并是 (乘法, OR);乘 $x$ 的标记是 (x,mask(x)),作用为 product*=x^len, mask|=mask(x),标记复合仍是 (乘法, OR)。
这种推导方式比“给模板加数组”可靠:先写摘要语义、合并律、标记作用、标记复合,再编码。
uint64_t;若质数更多应换动态 bitset。线段树每节点存各字符数,Lazy 表示整段被赋成某字符。查询得到 $cnt[c]$ 后,从左端开始按升/降字符顺序,把长度 cnt[c] 的连续段赋为 c。所有段总长等于原区间长且互不重叠;字符多重集不变、排列单调,因此恰是排序结果。每次 $O(26\log n)$。
counts = query_character_counts(l, r)
position = l
for c in alphabet_order(chosen_direction):
if counts[c] > 0:
range_assign(position, position+counts[c]-1, c)
position += counts[c]
x<=300 把质数宇宙压到 62 位,这是题目给出的关键可实现信号。预处理每个 $x\le300$ 的质因子掩码和每个质数的模逆。线段树合并区间乘积与掩码。查询后从 product 出发,对掩码每个质数乘 $(p-1)p^{-1}$。
节点乘积由模乘结合律正确合并;掩码 OR 恰表示左右区间质因子并集。区间乘操作对每个元素乘 x,所以总乘积恰乘 $x^{len}$,新增质因子恰为 mask[x]。归纳得查询摘要等于真实区间;Euler 乘积公式随后给出答案。每次 $O((\log n)+62)$。
summary = (product_mod, prime_mask)
combine(A,B) = (A.product*B.product mod MOD, A.mask OR B.mask)
apply_multiply(node, x):
node.product *= pow(x, node.length)
node.mask |= factor_mask[x]
query_phi(l,r):
product, mask = query(l,r)
for each prime bit in mask: product *= (p-1) * inverse(p)
CodeForces-1172F Nauuo and Bug(3300)把一段数组视为对输入累加器的函数,并在线段树节点合成函数摘要,回答区间函数作用。它训练“线段树维护函数而非数值”;仅部分相关,不作为后续前置。
把节点摘要与 Lazy 看成代数对象,能系统判断模板是否可用:摘要需有结合合并,标记需可复合,并满足标记对合并的作用一致性。矩阵、仿射函数、括号信息都可按同一视角设计。
先用纸面写出摘要/合并/作用/复合四张表,再编码。随机对拍时让乘数含多个质因子、重复质因子和 1,检查 OR 与指数更新边界。