理解区间非线性修改为何通常不能直接 Lazy,掌握 Beats 的“最大值、严格次大值、最大值个数”条件更新,并能用势能证明取模、约数替换等递归到叶的操作总复杂度。
前置:Lazy Segment Tree、摊还分析。
a_i=min(a_i,x),只保存最大值和区间和够吗?普通 Lazy 要求修改能由节点摘要直接更新,并可安全传给孩子。chmin(x) 在 $secondMax<x<max$ 时只影响最大值组,因此节点可直接更新:
$$ sum\mathrel{-}=(max-x)\cdot countMax,\qquad max\leftarrow x. $$
若 $x\le secondMax$,变化涉及至少两档值,必须下放。这种在节点条件满足时“击败”递归的结构称 Segment Tree Beats。
另一些操作没有固定摘要闭式,但存在稳定点或快速下降势能:取模让被改变值至少缩到原来一半;约数个数函数很快降到 2 并稳定。用节点最大值判整段是否已稳定,剩余有效叶修改总次数受势能约束。
secondMax 是严格次大,不是第二个元素;全相等段设为负无穷。chmin(parent.max)。countMax。chmin、区间最大值、区间和。max2<x,等号时两档将合并,摘要不足以更新新最大个数。递归遇到 max1<=x 直接返回;整段且 max2<x 调整最大组;否则下传父最大约束并递归孩子。直接更新条件保证受影响元素恰是最大值组,因此和、最大值、计数都准确;其他情况递归到能区分值档的位置,最终每个大于 x 的叶都被改且其余不动。
Beats 的严格复杂度分析较细:每次无法整段处理会使节点最大/次大结构发生实质变化,常用势能可证均摊近 $O((n+q)\log n)$ 到 $O((n+q)\log^2 n)$;本题标准实现可通过给定总规模。
range_chmin(node, x):
if node.max1 <= x: return
if fully_covered and node.max2 < x:
node.sum -= (node.max1-x) * node.countMax
node.max1 = x; return
push parent's max constraint to children
recurse and pull
a%=x,新值严格小于 $a/2$;包括 $x>a/2$ 时余数为 $a-x<a/2$。区间修改对最大值小于模数的节点剪枝,否则下沉至叶。每个叶真正被取模一次后至少减半,所以在两次赋值之间最多有效修改 $O(\log A)$ 次;每次访问再乘树高,得到 $O((n+q)\log A\log n)$ 的安全上界。查询与赋值为普通 $O(\log n)$。
range_mod(node, x):
if disjoint or node.maximum < x: return
if leaf: value %= x; return
recurse to children; pull sum and maximum
筛法为每个约数 $d$ 给倍数加一,得到 divisor_count。替换操作在 maximum<=2 的节点停止,否则递归到叶替换。被跳过段所有元素确为不动点;未跳过段最终访问每个尚不稳定叶并精确更新。每点有效变化次数为很小的 $O(\log\log A)$,总访问均摊可控。
precompute D[x] for x <= 1e6 by divisor sieve
replace(node):
if node.maximum <= 2: return
if leaf: value = D[value]; return
recurse; pull sum and maximum
CodeForces-679E Bear and Bad Powers of 42(3100)维护区间加/赋值,并反复避开坏值 $42^k$。它要求节点保存到下一个坏值的最小距离,在触碰阈值时局部修复;用于训练“维护下一次结构变化的时间”,不作后续前置。
Beats 不是任意非线性修改的万能模板。能否使用取决于:节点是否能识别少数受影响值档、直接更新后摘要是否闭合、失败下沉是否有势能保证。
max2<x 为什么必须严格?maximum<=2 为什么是约数替换的充分剪枝?先把 Beats 与朴素数组对拍,随机操作刻意令 x 等于次大值。势能题记录每个叶实际被访问次数,观察上界而非只看总耗时。