像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

【题解】P5609 | 线段树 分段函数维护 人类智慧

对数据结构的爱,未曾衰减?

本题解参考了 Saliеri 的题解。


首先对于这类数经过操作求最终值的问题,可以比较简单地想到一个分块做法:

将序列分块,每块长度为 O(n),对于每一块我们需要维护某个值进去会以另外某个值出来,然后就可以在在整块上快速查询然后模拟散块,考虑这个某个值进去会以另外某个值出来的函数,令其为 f(x),容易发现 f(x) 是一个分段函数且每段是一次函数,其段数是 O(区间长度) 的,考虑对于每个块求出这个分段函数。

维护该分段函数的分界点 ki 进入该区间后出来且至少减去了 ip 的最小值。

引理:ki 单增且 kiki1p

证明:因为 ki 是最小的满足至少减去了 ip 的值,考虑减去 ip 后一定变成了 0 或负数,至少需要加上 p 才会能够继续减。

考虑增量维护 {ki},新的 ki 发生改变仅当加上新加入的这个 ax 后可以减去 p,即 ki+1 可以被如下更新:

需要满足能够在前面部分减去 ip 并加上 ax 后大于等于 p,故需要满足如下条件:

ki+1min(ki+1,max(ki,pax+ip))

且需要满足条件 pax+ip<ki+1,该条件意味着 能够满足在这次能被减去的数不能在之前被减去了超过 i 次,否则到该数时的值就不是 Aip+ax 了,可能会减去更多。

所以我们就有了个 O(nn+mnlogn) 的做法,但是不太能过,应该怎么继续下去找到一个 polylog 的做法?

之所以要分块是因为这个分段函数看上去很不可多元合并,只可以单元添加,如果可以多元合并就可以建出线段树,因为本题中的分段函数性质很特殊,考虑设计如下一种合并方式:

枚举在左侧和右侧的被减去的次数 kli,krj,试图判断能否在整个区间构成减去 ki+j 次的情况,记录左侧的和为 S,则有如下更新:

类似上面,若满足条件 krjs+ip<kli+1 才可以去更新,即在左侧被减去了 i 次,否则会减去 i+1 次或更多。

对于满足条件的 i,j 有如下更新:

ki+jmin(ki+j,max(kli,krjs+ip))

直接枚举 i,j 并进行合并的复杂度是平方的,我们继续挖掘性质。

V(i,j)=max(kli,krjs+ip)

定理:对于一个固定的 i+j,被 i 最小的 i+j 更新到是最优的。

证明:试比较 V(i,j),V(i+1,j1),因为有 krjs+ip<kli+1,所以一定有 max(kli,krjs+ip)<max(kli+1,krj1s+ip)

所以我们只需要对每个 i+j 求出最小的 i 可以去更新它,又因为可以更新的条件是 krjs<kli+1ip,随着 i 增大而越来越松,所以用双指针枚举最大的 j 即可。

于是我们求出了所有线段上的分段函数的形态,查询时直接在线段树上依次对 O(logn) 个分段函数进行二分,时间复杂度 O(nlogn+mlog2n)

posted @   寂静的海底  阅读(48)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起