关于吉利线段树
Posted guessycb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于吉利线段树相关的知识,希望对你有一定的参考价值。
引言
这玩意儿又称(Segment Tree Beats) 。由吉老师、(Picks)、美国队长三位知名毒瘤发明。
我的精神受到了污染......
线段树简介
线段树什么的太难了,不是很会啊.....
线段树最强的地方在于,如果标记支持合并,那么我们就能够快速进行区间修改了。
一类特殊标记
维护这样一个标记((a,b)) ,表示(x o max(x + a , b)) 。
显然标记可合并:((a,b) + (c,d) = (a + c , max(b + c , d))) 。
这个标记可以同时处理区间加法、区间覆盖,对应为((add,-inf))、((-inf , cov)) 。
这个标记还能取(max):(max((a,b) , (c,d)) = (max(a,c) , max(b , d)))
由于该分段函数取上平面交后段数不变,所以支持维护历史最大值,可以说是相当好用了。
然而这个东西在解决历史最小值,区间取(min)等一系列问题上无能为力,所以我们需要另辟蹊径。
一类历史最大、最小值问题
设当前最大值为(mx)、最小值为(mn)、修改增量标记为(t)。
设历史最大值为(hmx),历史最小值为(hmn)。
直接维护不好维护,我们考虑维护历史最大标记(mxt)、历史最小标记(mnt)。
可以理解为,这个历史最大标记(mxt)是修改标记(t)的一个最大前缀和,历史最小标记(mnt)类似。
那么下放就很简单了。
先用新的前缀和更新所有历史最优值:
(mx + mxt' o hmx)、(mn + mnt' o hmn)、(t + mxt' o mxt)、(t + mnt' o mnt) 。
然后再把当前值改为真实值:(t' o t)、(t' + mx o mx)、(t' + mn o mn) 。
当然这些标记不一定要是加法标记。
只要是支持合并,并且能够定义大小关系的标记,我们都可以这么做。
例题:
[UOJ164]【清华集训2015】V ; 代码
一类趋近问题
当修改操作逐渐使得元素趋近于相同时,往往就可以搞事情。
目前已知的这类操作:
- 区间开根 + 加法 + 求和
- 区间或 + 与 + 求和
- 区间除法 + 加法 + 求和
解决方案就是:若该修改对当前区间影响相同则打标记,否则暴力递归处理。
比如,对于开根、除法操作,记录区间最小、最大值。
对于区间或 + 区间与操作,记录区间内每一位是否相同(用位运算即可所有位一起实现)。
例题:
[BZOJ5312]冒险 ; 代码
[UOJ228] 基础数据结构练习题 ; 代码
一类区间最值问题
势能分析之类的略过,反正我口胡的势能分析连我自己都不知道对不对。
以区间取(max)为例。
维护区间最小值(mn)、区间次小值(se)。
对于区间对(x)取(max)操作,首先定位到(log)个线段树结点,然后从它们开始(dfs)。
设当前点为(u)。
若(x leq mn_u) ,显然该操作对区间无影响,(return) 。
若(mn_u < x < se_u),我们维护最小值修改标记(t),把最小值改为(x)即可。
若(se_u leq x) ,暴力递归。
显然加法操作可以直接维护,额外维护一个标记(d)表示最小值之外的其他数的修改量。
注意一点:(pushdown)时,若(se_u = inf) , 那么(se_u) 不能被修改,因为我们要保证势能分析时关键点的数量。
同时(pushdown)的时候,我们要讨论儿子的每个值对应哪个标记,进行对应修改。
区间取(min)是一样的,维护区间最大值(mx),区间次大值(se)即可。
需要注意的一点:
当我们需要同时支持区间(max)、区间(min)的时候,取(max)时要考虑它对最大值的影响,取(min)时要考虑它对最小值的影响。
我们的加法标记要分为三类:(mn.t)、(mx.t)、(md.t),分别对应区间最大值增量、区间最小值增量,非最大最小值增量。
一样的(pushdown)时要考虑儿子每一个值对应的修改应该是哪一个,然后用其属于的修改标记进行修改。
例题
[BZOJ4695] 最假女选手 ; 代码
[BZOJ4355] Play-with-sequence ; 代码
当所有问题混到一起?
线段树各种操作大融合。
没什么好说的,按照上面的方法一个一个实现即可。
代码必须模块化,并且是条理清晰的模块化,否则这种题是调不出来的。
例题
[UOJ169] 元旦老人与数列 ; 代码
[UOJ170] Picks loves segment tree VIII ; 代码
以上是关于关于吉利线段树的主要内容,如果未能解决你的问题,请参考以下文章