KTT 做法。这里的变量可能和原题有一定不同。
以下令第
i 个波特当前的移动速度为
ki,当前时刻的位置为
bi。初始
ki=0,bi=ai。
首先离原点最远的显然就是
bi 最大或者
bi 最小的,这里只介绍
bi 最大的情况,
bi 最小的情况只需要把初始位置和操作取相反数再求最大即可。
考虑第
p 次操作和第
p−1 次操作之间的
Δt=tp−tp−1 秒中发生了什么,对于第
i 个波特,显然是以
ki 的速度匀速移动了
Δt 秒,有
bi←bi+ki⋅Δt,那就是在每次操作之前,所有
bi 都增加
ki⋅Δt。
现在需要支持以下三种操作:
- 给定 Δt,∀1≤i≤n,bi←bi+ki⋅Δt,即全局修改 bi。
- 给定 pos,v,kpos←v,即 command 操作。
- 求 maxbi,即 query 操作。
然后这个
k 和
b 可以看成一次函数,第一个操作就是所有一次函数左移
Δt 个单位,第二个操作就是修改其中一个一次函数的斜率,这个很像 KTT 的形式。
考虑用 KTT 做,每个节点维护三个值:
maxk,maxb,w。
maxk 和
maxb 表示当前
b 值最大(零点时函数值最大)的一次函数的
k 和
b,
w 就是阈值,即子树内的一次函数再左移
w 单位之后
maxk,maxb 会改变,如果
max 不会改变则
w=∞,一个叶节点
[i,i] 的
maxk=ki,maxb=bi,w=∞。
对于
maxk,maxb 这两个值,合并两个区间
[l,mid],[mid+1,r] 是简单的,对于
w,则有
w[l,r]=min(w[l,mid],w[mid+1,r]),同时,如果
[l,mid] 和
[mid+1,r] 的函数
f1(x)=max[l,mid],kx+max[l,mid],b 和
f2(x)=max[mid+1,r],kx+max[mid+1,r],b 在
x≥0 有交点
(px,py),那么
max[l,r],k,max[l,r],b 肯定会在
px 处(或者前面)发生改变,因此还有
w[l,r]←min(w[l,r],px)。
对于所有
bi 都增加
ki⋅Δt 这个操作(全体左移
t 格),维护懒标记
lazy[l,r] 表示
[l,r] 的子树中函数需要左移
lazy[l,r] 格。修改一个节点时,如果需要左移
p 格,则
maxb←ki⋅p,同时
w←w−p,然后懒标记也同时修改一下就行了,在
command 时再下传。然后对于全体修改,如果
Δt<w[1,n] 就修改节点
[1,n] 就可以,否则就重构子树,就是递归更新左右子树,令当前节点为
[l,r],如果
lazy[l,r]+Δt 小于子节点的
w 就继续递归更新,否则直接修改子节点并打上懒标记,然后 pushup。
pushdown 的时候应该是不用判是否超过阈值的,因为如果
Δt<w[1,n] 显然
Δt 也小于其子节点的
w。
对于一次
command 操作,直接找到
[pos,pos],然后逐个 pushup,更新
maxk,maxb,w 就行了。
对于
query 操作,显然
max[1,n],b 即为当前时刻答案。