注意到小段长度
>1 肯定不优,直接记
fi 为
[i,i] 是一个小段,在
≤i 的前缀划分的最大段数,暴力是
O(n2) 的,可以发现转移来的
fj 是一个前缀再加上
O(logV) 个零散点(证明和后文的一个结论一致,这里略去),故可以做到
O(nlogV)。但是这连不带修、区间询问都做不了!
我们肯定希望这个 dp 数组有什么更好的性质,比如……递增?修改
fi 定义为
≤i 的前缀划分最大段数,姑且认为
i 单成一段(否则并到前一段上,向
fi−1 取个 max 即可)考虑转移,可以说明条件和上面是一致的,即需
j<k<i∑ak>max(ai,aj)。可能导致的问题是这个 dp 对应的一个方案是
[l1,r1],[l2,r2],[l3,r3],认为三者分别是大/小/大段,然而却只保证了
l1≤i≤r1∑ai>al2 和
l3≤i≤r3∑ai≥ar2,并不必然合法。我们将其映射到一个段数相同的且保证合法的方案:若
al2≤ar2,改为
[l1,r1],[l2,l2],(l2,r3],否则改为
[l1,r2),[r2,r2],[l3,r3],修改后任意大段总和不变小,故对于更左、更右的修改仍然可以做到;而当小段在最左/最右段时也有类似处理,不再赘述。
此时我们可以断定,
fi 肯定是由某个最大的满足条件的
j 转移来了,因为
f 递增。再要求忽略前缀 max 的转移,
j 需满足
∃j<p≤i,j<k<p∑ak>max(aj,ap),有结论:
i−j 是
O(logV) 的,一个松的界是
2logV。若有
ap−1>ap,此时仅考虑
aj 对和的限制,则
p−j≤logV,因为每遇到一个不合法
j 和就会翻倍;否则
ap−1≤ap,找到极长的这样子的递增段
[p′,i],长度也是不大于
logV 的,因为前缀和都是不断翻倍的。
则每次单点修都只会修改一个长度
≤2logV 区间的
i 对应的
j,查询就是从
r 开始不断跳
j 直到跳出
[l,r],看跳了几次。这不就是我们
P3203 弹飞绵羊 吗!由于重算一个
i 的
j 是
O(logV) 的,而
B=n≥2logV,故每次修改至多仅重构两个块,总复杂度就是
O(nlogV+q(n+log2V))。