互测赛(4)总结

0.前言

其实是 KTT 学习笔记。

1.正文

KTT,全称 K什么 T什么 T什么,主要用来解决区间加正数,求区间最大子段和问题。

如果没有修改操作,这个东西是好做的。我们直接使用线段树,每个节点维护当前节点的区间和,区间最大子段和,最大前缀和和最大后缀和。设其分别为 \(sum,val,lmax,rmax\)pushup 是简单的:

  • \(p.sum=ls.sum+rs.sum\)
  • \(p.lmax=\max(ls.lmax,ls.sum+rs.lmax)\)
  • \(p.rmax=\max(rs.rmax,rs.sum+ls.rmax)\)
  • \(p.val=\max(ls.val,rs.val,ls.rmax+rs.lmax)\)

这样就可以做到 \(O(n+q\log n)\) 的时间复杂度。

如果有区间加正数的操作,这个问题就变得相当困难了。

(Mortis尖叫.jpg)

假设,现在给某个区间加了 \(d\),并且取 \(\max\) 时决策不变,那么 \(val\) 就会变成 \(val+d\times Len\)。其中 \(Len\) 是最大子段和对应的区间的长度。

不过这样的情况并不会经常出现。但是这是有启发性的。我们可以把 \(val+d\times Len\) 看作一个和 \(d\) 相关的一次函数。那么每次 pushup 时就是一次函数取 \(\max\)(这里是根据 \(d=0\) 时的取值来取 \(\max\),原因待会就能理解)。

如何解决决策变化的问题?通过计算一次函数的交点,我们可以得到一个阈值 \(x\),它表示当前节点在 \(d\geq x\) 时,\(lmax,rmax,val\) 中就会有至少一个一次函数的取值(就是 pushup\(\max\) 取的是哪个一次函数)变化。如果现在加入的 \(d < x\),那么就可以直接将所有一次函数的 \(b\) 值更新,这相当于我们对一次函数进行了向左平移。也就是说,\(x\) 值也要减去 \(d\)

否则,直接往两边递归,直到发现某一个子树满足其 \(d < x\)。这就相当于一次函数平移后,我们的一次函数交点已经移到 \(0\) 之前了。那我们钦定按照位置 \(0\) 的值取 \(\max\) 就不行了,需要重新计算。你会发现,这里的一次函数在正常时取值就应该是 \(0\) 位置的取值(即答案),将其变成一次函数只是为了方便我们进行修改操作。更新完子树后再 pushup 就行了。

因为当前一次函数的决策和子树的一次函数有关,所以当子树的一次函数变化时,当前节点的一次函数也可能变化。也就是说,\(x\) 也需要 pushup,并且在 pushup 时需要和 \(ls.x\)\(rs.x\)\(\min\)。除此之外,还需要计算当前节点三个决策中各个一次函数的交点,然后再取 \(\min\)。然后维护一下一次函数就做完了。

看着很暴力,但是时间复杂度其实是三个 \(\log\) 的。不会分析。

写的啥呀。

posted @ 2025-11-03 12:13  Just_int_mian  阅读(57)  评论(10)    收藏  举报