李超树学习笔记

先说一些题外话

其实很早就有这些这个的欲望了。。。php

可是因为种种缘由(包括班主任),一直咕到如今。。。html

咕咕咕。。。算法

不能再咕下去了!数据结构

因而熬夜来写这个。函数

步入正题

先看一个例题:BZOJ1568: [JSOI2008]Blue Mary开公司post

其实这个算是裸题了。。。
固然我作的第一道李超树的题不是这个。。。
题目要求区间内的全部直线的最高点的最大值。
而且带插入。
裸的暴力$O(nm)$对吧。
而后呢?
第一想法是——分治!
将一个区间$[l,r]$分红$[l,mid],[mid+1,r]$两个区间,递归求解。
合并答案就取最大值就好。
这样,咱们便得出来一个$O(mn\log_2n)$的算法。。。
你会说:“这个算法复杂度还没暴力跑得快,我要他干吗???”
诚然,暴力跑得比它快得多。。。
可是你以为这个算法若是没有用的话,我会讲它吗?
咱们回头看咱们分治的过程:将区间一分为二,且区间大小相等。
若是你有 像我同样的超高的$DS$水平,你就会发现这个过程和某个数据结构的过程好像啊!
没错!这个数据结构就是—— 线段树
是否是很厉害!
为何?由于咱们找到了一种数据结构来维护这玩意了!
因此线段树每一个点存区间最大值就好。
$BUT$!这么作还有一个问题:插入线段怎么办?
你会想:用最大值覆盖不就行了?
那么问题又来了:线段是有斜率的。
也就是说,在不一样的点,线段的函数值是不一样的。
你怎么知道当前的点的函数值是多少呢?
可能你又会想:那我就暴力带值进线段,把函数值算出来不就行了?
那么恭喜,你离深渊愈来愈近了。
你会发现你的每一次维护都会涉及到最多$4n$个节点。
那和暴力有什么区别???
因此这个方案被咱们舍弃了。
那怎么办呢?
对于这个问题, 国家队队爷李超提出一种解决办法:
咱们把线段树中存的值从区间最大值改成 区间中值最大的直线
每一个节点至少会存一条直线。
可是多条直线呢?
咱们能够打一个标记,说明再这个区间内至少有一个两条直线的转折点。
而后递归插入直线。
具体作法是这样的:
假设原来在$[l,r]$这个区间内只有一条直线$f_1(x)=k_1x+b_1$。
如今要在区间内插入一条新直线$f_2(x)=k_2x+b_2$。
而后即是分类讨论:

1. 若是$f_1(l)\geq f_2(l),f_1(r)\geq f_2(r)$:ui

说明$f_2(x)$在这个区间内被$f_1(x)$吊打,那么不作任何操做;url

2. 若是$f_1(l)\leq f_2(l),f_1(r)\leq f_2(r)$:spa

说明$f_1(x)$在这个区间内被$f_2(x)$吊打,那么直接替换便可;3d

3. 若是$f_1(l)\geq f_2(l),f_1(r)\leq f_2(r)\text{或者}f_1(l)\leq f_2(l),f_1(r)\geq f_2(r)$:
说明两直线在这个区间内有交点。
这时,咱们取区间中点$mid$,判断两直线在$[l,mid]$之间是否相交:
如果,则右区间$[mid+1,r]$赋为在上方的曲线,左区间递归求解;
不然,左区间$[l,mid]$赋为在上方的曲线,右区间递归求解。
这样,咱们的一次插入直线操做完成。
而递归修改最多会涉及到$\log_2n$个节点。
因此一次修改的复杂度上限为$O(\log_2^2n)$。
而后,这题还须要用到标记永久化。
即咱们不下传标记,在求区间最大值的时候,每次访问到一个被询问区间包含的区间,把答案和这个区间所维护的线段的最大值取$max$。
而后这个题就作完了。
不得不说很是的机智啊!
因此这种线段树被称为—— 李超树
复杂度$O(m\log_2^2n)$。
疯狂维护半平面交。。。
代码的话。。。能够去题解里找:

BZOJ1568: [JSOI2008]Blue Mary开公司

再推荐两道练手题:

相似的板子题:

BZOJ3165: [Heoi2013]Segment

我作的第一道李超树题:(万事开头难。。。)

BZOJ4515: [Sdoi2016]游戏

后记

其实李超树不建议在考场上写。
由于这玩意的修改很容易写炸。。。
而且查错及其恶心。。。
对于大多数$DS$能力不是极其强悍的$OIer$来讲,性价比并非很高。
由于通常这种题的部分分都比正解的性价比高。。。
因此不是队爷不写正解。。。
而对于我这个菜鸡$AFO$选手来讲,能够浪一浪。。。
出题人,我劝你善良。。。
相关文章
相关标签/搜索