像潮落潮涌,送我奔向自由。|

寂静的海底

园龄:3年2个月粉丝:59关注:15

2023-02-06 17:53阅读: 143评论: 0推荐: 1

浅谈近期用到的segment tree beats technology

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

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

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


CF1572F Stations

diff:3300

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

考虑如何维护 ri 的同时处理这种影响。

ri 维护一棵 segbeats ,每个节点上套路地维护 mx,se,cnt , 接下来就是考虑每次操作对后面的影响 。

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

复杂度因为 Segment Tree beats  分成了均摊 O((n+q)logn) 个区间,每次区间加 O(logn) ,所以是 O((n+q)log2n) 的。

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

时间复杂度 O((n+q)log2n)


P4198楼房重建

diff:2800(目测)

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

考虑没有修改,静态问题是从前往后,数一遍 min(k1ki1)<ai 的个,本质就是每次把目前的最小值和 aimin , 取成功了就记一次数。

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

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

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

维护一棵区间取 min ,查询被取 min 的次数 的 Segment Tree beats  即可。

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

时间复杂度 O(n+qlogn) ,实际运行速度略快于 O(n+qlog2n) 做法。


NowCoder7615D

diff:3000+

题意:求排列的极长上升子序列的个数 , n200000

首先有个较为显然的O(n2) dp

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

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

那么:

f(i)=j<if(j)[aj<ai,j和i之间不存在 ak > aj]

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

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

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

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

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

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

于是你就把一道差不多 diff 3000 的题转化成了 差不多 diff 3300 题啦。。。。

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

posted @   寂静的海底  阅读(143)  评论(0编辑  收藏  举报
历史上的今天:
2022-02-06 atcoder近期比赛记录
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起