浅谈近期用到的segment tree beats technology
\(\text{Segment Tree beats }\)是势能线段树的全称,泛指这种在某些情况下打tag,在某些情况暴力子树,复杂度通过势能分析证明的线段树。
主要用途:区间取 \(\min/\max\) , 区间开根号 , 区间除 \(x\) 取整 之类不易打tag处理的区间操作。
虽然以前会一点,但是根本没做啥题,记一些题在此篇。
\(\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 )\) 。
\(\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 }\) 套树状数组就可以解决了。
本文已经结束了。本文作者:ღꦿ࿐(DeepSea),转载请注明原文链接:https://www.cnblogs.com/Dreamerkk/p/17096222.html,谢谢你的阅读或转载!

浙公网安备 33010602011771号