UOJ Logo EntropyIncreaser的博客

博客

区间增量最大子段和的 polylog 做法

2019-09-19 22:07:18 By EntropyIncreaser

先抛出目前得到的结果:区间给每个数加 $x (x \ge 0)$,区间查询最大子段和,我们有一个 $\mathcal O(n\log^3 n + m\log^4 n + q\log n)$ 的做法(不排除可能通过一些分析发现这个算法的复杂度实际上更低)。

其中,$n$ 是序列长度,$m$ 是修改次数,$q$ 是询问次数。

我们考虑当前情况下先用传统的方法用线段树维护最大子段和,即维护 $sum, lmax, rmax, totmax$,也就是:

$$ \begin{align} sum &= ls.sum + rs.sum\\ lmax &= \max(ls.lmax, ls.sum+rs.lmax)\\ rmax &= \max(rs.rmax, rs.sum+ls.rmax)\\ totmax &= \max(ls.totmax, rs.totmax, ls.rmax + rs.lmax) \end{align} $$

但是我们同时还维护一个额外的信息,就是当前这个值在本区间 $+x$ 后的情况,也就是说我们存储的是一个一次函数 $kx + b$,我们将每个量都看成一个一次函数

在这一情况下,当所加的 $x$ 极小,我们每个 max 符号选取的位置不会发生变化,那么我们还想记录最小的 $x$,表示将这个子树内的数都 $+x$ 后,某个 max 改为选取另一条直线,我们称这是一次“击败”事件。在这种情况下我们向下递归到该节点并重新选取当前 $x$ 下值最大的直线。

接下来证明本算法的时间复杂度。

我们记一个包含 max 比较的变量的 rank 值 $r(v, para)$:

  • 对于 $r(v, lmax)$ 或 $r(v, rmax)$:对于该变量的决定式 $f(x) = \max(a(x), b(x))$,rank 值表示当前 $a, b$ 中斜率大于 $f$ 的斜率的直线的数量乘以 $d^2$,$d$ 为该节点到根节点距离的节点数。
  • 对于 $r(v, totmax)$:对于该变量的决定式 $f(x) = \max(a(x), b(x), c(x))$,rank 值表示当前 $a, b, c$ 中斜率大于 $f$ 的斜率的直线的数量乘以 $d$。

我们直接定义势能 $\Phi = \sum_v \sum_{para} r(v, para)$。

我们现在考虑最坏实现,那就是每次击败都重新从根节点向下找到该节点修改。分析一次击败事件的摊还代价,我们记单位时间为一次线段树修改,因此这里算出的代价换算到时间复杂度后要乘以一个 log:

  • 发生一次 $lmax$ 或 $rmax$ 的击败(此处以 $lmax$ 举例):
    • 当前节点的 $\Delta r(v, lmax)$ 显然是 $-d^2$,因为替换上来的函数显然斜率更大。
    • 父节点的 $\Delta r(prt, lmax) \le (d-1)^2$,因为替换上来的函数有可能使得在上方的节点增加一次被击败的可能性。
    • 父节点的 $\Delta r(prt, totmax) \le d - 1$,同理。
    • 其他的 rank 值不应该有改变,注意不要混淆一个概念:如果此时上面有的函数因为下面的更新以及引发了修改,那应当视作是另一次击败事件。
    • 综上,我们计算这次击败的势能变化:

$$ \Delta \Phi \le 1 -d^2 + (d-1)^2 + d-1 = 1-d \le 0 $$

  • 发生一次 $totmax$ 的击败:
    • 当前节点的 $\Delta r(v, totmax)$ 是 $-d$。
    • 父节点的 $\Delta r(prt, totmax) \le d - 1$。
    • 其他的 rank 值不应该有改变。
    • 综上,我们计算这次击败的势能变化:

$$ \Delta \Phi \le 1 -d + d-1 = 0 $$

可以看出,我们完全消解了击败操作的摊还代价!这意味着所有的时间复杂度由初始势能以及修改造成的额外势能改变贡献。

$$ \Phi_0 = \sum_v \sum_{para} r(v, para) \le \sum_v d + 2d^2 = \Theta(n\log^2 n) $$

显然一个节点 $v$ 的 $\sum_{para} r(v, para) \le d + 2d^2$,而一次区间修改会使得 $\mathcal O(\log n)$ 个节点的 rank 变大,因此 $\Delta \Phi = \mathcal O(\log^3 n)$。

别忘了这个计量的是线段树上的操作次数……因此实际复杂度是 $\mathcal O(n\log^3n + m\log^4n)$,询问显然是 $\Theta(q\log n)$ 没话说。


UPD

我们考虑每个节点的 $lmax$ 和 $rmax$ 的决策发生变化的次数。注意到 $lmax$ 的决策点只会递增,而在一个节点发生斜率切换的必要条件是决策位置从 $[l, mid]$ 切换到了 $[mid+1, r]$。每个节点最多触发一次,故 $lmax, rmax$ 的总共额外复杂度是 $\Theta(n\log n)$。

因此我们现在知道 KTT 维护 $lmax$ 和 $rmax$ 的总共 dfs 到的节点数是 $\Theta((n + q)\log n)$ 的。我们沿用势能分析,是 $\Theta((n+q)\log^3 n)$。

评论

cszmc2004
dalao受我深情的一拜!orz
OldDriverTree
orz
mrsrz
orz
Ynoi
%EI
foreverlasting
orz
LanrTabe
orz
liu_cheng_ao
这个问题为什么不能直接维护区间关于前缀和、后缀和的凸包呢?
liu_cheng_ao
如果问题修改成:每个位置有个固定系数 $K_i$,区间“加” $x(x>0)$ 定义成区间内下标为 $i$ 的位置加 $x\cdot K_i$,(相当于一个长 $\sum_i K_i$ 的分段序列的原问题),这套均摊分析还能成立吗?
yurzhang
Orz
Cheng_yf
orz
IAKIOI
orz
ANO
ORZ
wlzhouzhuan
Orz LBT
Smallbasic
Orz EIddjxd
loveJY
Orz EI
ycx_akioi
0rz
DPair
Orz
gxy001
Orz
zhltao
⭐rz
wh2005
Orz

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。