浅谈近期用到的segment tree beats technology

\(\text{Segment Tree beats }\)是势能线段树的全称,泛指这种在某些情况下打tag,在某些情况暴力子树,复杂度通过势能分析证明的线段树。

主要用途:区间取 \(\min/\max\) , 区间开根号 , 区间除 \(x\) 取整 之类不易打tag处理的区间操作。

虽然以前会一点,但是根本没做啥题,记一些题在此篇。


CF1572F Stations

\(\text{diff:3300}\)

考虑每个点有一个“最大影响范围” \(r_i\) ,那么每次操作就是对 \(r_i\) 区间取 \(\min\) , 需要维护的东西是 \(\sum _{p<i} [r_p\geq i]\) , 及其区间和 ,发现每个点可以影响的是一个区间。

考虑如何维护 \(r_i\) 的同时处理这种影响。

\(r_i\) 维护一棵 $\text{segbeats} $ ,每个节点上套路地维护 \(mx,se,cnt\) , 接下来就是考虑每次操作对后面的影响 。

有一个线段树上对应的区间被修改,且取 \(\min\) 值介于 \((se,mx)\) 之间 ,则需要打标记,这意味着这些 \((se,mx)\) 间的值都变成了 \(c\) 所以实际上是 \([c+1,mx]\) 少被覆盖了 \(cnt\) 次 , 再在一棵 \(\text{Fenwick Tree}\) 上减就行了。

复杂度因为 \(\text{Segment Tree beats }\) 分成了均摊 \(O((n+q) \log n)\) 个区间,每次区间加 \(O(\log n )\) ,所以是 \(O((n+q) \log ^2 n )\) 的。

单点修改就是看改长了还是改短了,进行区间加/减即可。

时间复杂度 \(O((n+q) \log ^2 n )\)


P4198楼房重建

\(\text{diff:2800}\)(目测)

在线有神仙 \(O(n + q \log^2 n)\) 线段树做法,然而我太菜了,没有想到,但是题解区貌似没有找到离线单 \(\log\) 做法 。

考虑没有修改,静态问题是从前往后,数一遍 \(\min(k_1\dots k_{i-1} ) <a_i\) 的个,本质就是每次把目前的最小值和 \(a_i\)\(\min\) , 取成功了就记一次数。

在线不好处理,考虑离线,观察在时间上不具有太多特征,唯一的优点在于“单点查”,而在序列上有许多特征:单调性,前缀影响。

再加上刚刚静态问题的方法。

于是考虑时空转置,做扫描线,把时间轴看作序列,每一次修改就是在对应位置(时间) , 对生效时间段(区间)进行取 \(\min\) ,询问前缀可以看作在位置对应时间单点查询时间对应的位置被取 \(\min\) 的次数。

维护一棵区间取 \(\min\) ,查询被取 \(\min\) 的次数 的 \(\text{Segment Tree beats }\) 即可。

将标记换成二元组 \((Tag,cnt)\) 表示区间最大值被取 \(\min\) 成了\(tag\) , 取了 \(c\) 次,正常下放即可。

时间复杂度 \(O(n + q\log n)\) ,实际运行速度略快于 \(O(n + q\log^2n)\) 做法。


NowCoder7615D

\(\text{diff:3000+}\)

题意:求排列的极长上升子序列的个数 , \(n\leq200000\)

首先有个较为显然的\(O(n^2) \text{ dp}\)

在序列开头填 \(0\) , 末尾填 \(n + 1\)

$f(i) : $ 1~i 中 i 结尾的极长上升子序列的个数 。

那么:

\(f(i) = \sum_{j<i}f(j) [a_j<a_i ,\text{j和i之间不存在 ak > aj}]\)

我没有考虑这个dp如何优化,其实只用在值域上建 \(\text{Segment Tree beats }\) + \(\text{set}\) 就可以大力维护了。

另一种做法: 考虑他为啥是个排列,这个时候有一种套路就是把数从小到大地加进去,就可以少考虑有关值域的东西了。

于是我们按从小到大加入每个数,( \(inv\) 指逆排列 )。

每次新加入的数都是最大的,加入后前面已经加入的数都不能像后面转移了。

并且每个点自加入后可以转移的范围是单调不加的 , 且是一个区间中未加入的数。(只被取 \(\min\) )。

于是进行的操作就是对前面点\([1,inv_i - 1]\) 进行区间取 \(\min\) , 以及查询可以覆盖到这个点的权值和。

于是你就把一道差不多 \(\text{diff 3000}\) 的题转化成了 差不多 \(\text{diff 3300}\) 题啦。。。。

就像上面的第一题一样,用 \(\text{Segment Tree beats }\) 套树状数组就可以解决了。

posted @ 2023-02-06 17:53  寂静的海底  阅读(207)  评论(0)    收藏  举报