李超线段树 学习笔记

李超线段树 学习笔记

引入

最近一直在做斜率优化的题,然而只会傻傻维护凸包,一到横坐标不单调,就涉及到手打平衡树,但是我实在不想学平衡树了,所以就准备掏出解决处理直线的大宝贝——李超线段树

功能

有两种操作:
插入一条表达式为 L:y=k×x+b 的直线,给出 k,b
给出 t,求当前所有直线中与直线 x=t 交点的纵坐标最大是多少

实现

原理

维护区间的中点对应的最大值的直线,用到了标记永久化的思想

维护方法

修改

(偷了两张CSDN博主的图)

image

如当前情况,蓝色的直线是我们加入的直线,如果它比这个区间所有的都大(完全覆盖),那么就把原有线段换成这条直线;反之则直接舍弃。

下一种情况就是不完全覆盖(有交点)

image

  • 首先对于当前这个大区间,现在应该取 f(mid) 更大的直线作为当前区间的标记,那么对于整个区间都是如此吗?

  • No,可以看到两条直线在 [l,mid] 之间是存在交点的, 那么在左区间的某个位置,f(mid) 的大小关系就可能发生变化,所以我们需要递归进入有交点的区间来进一步修改

查询

和标记永久化的线段树查询一样,我们查询一个位于 x=t 的点对应的最大函数值,就要一直从 [1,n] 的直线,一直查询到 [t,t] 的直线,最后取所有可能的最大值,如下图:

image

我们要把橙色、绿色、蓝色、黄色区间的直线之间所有的最大值都取到。

例题

分析

例题用Build Bridges作为板子,本题写出来的状态转移方程是:

fi=min(fj+(hihj)2+sumwi1sumwj)

按照正常斜率优化的套路写出来的话,原式就变成了:

fi=(hi2+si1)+(2hi)hj+(fj+hj2sumwj)

这时候你发现我们要作为斜率的(2hi)并不单调了,而且插入的点 (hi,fi+hi2sumwi)横坐标也不是单调的,所以这个时候就要把方程换一种写法然后使用李超线段树了:

fi=(hi2+si1)+(2hj)hi+(fj+hj2sumwj)

可以发现前面是常数项,后面很像一个直线的形式了,我们可以看成给出一个横坐标,求 y=(2hj)x+(fj+hj2sumwj)的最小值。

其中我们每给出一条直线,就看成插入 ki=2hi,bi=fi+hi2sumwi的一条y=kix+bi的直线,并且在插入之前查询之前存在的所有直线,使得当前的横坐标hi对应能取得最小值对应的函数值,然后再插入这条直线。

注意一开始要让k[0]=b[0]=INF,不然第一条直线甚至都无法插入

Code

注意

写斜率优化的时候完全不用考虑直线的左右端点,直接插入和查询就是了,因为你插入的这个直线一定是无限长的,所以可以把所有的横坐标都囊括,因为我们用当前线段去更新这个区间的前提,就是这个区间被完全包括在这个线段之内。
但是如果插入直线的时候并不是无限长的,我们就要先按照定义找到被完全包含于这条直线的线段区间,然后再对它以及它的子线段递归进行更新。
普通李超线段树的插入写出来就是这样的:

struct SegmentTree{int idx,l,r;}rt[x];
int k[maxn],b[maxn];
int calc(int x,int idx){return 1ll*k[idx]+b[idx];}
inline void modify(int x,int l,int r,int idx)
{
int mid=rt[x].l+rt[x].r>>1;
if(l<=rt[x].l&&rt[x].r<=r)
{
if(calc(mid,rt[x].idx)>calc(mid,idx))rt[x].idx=idx;
modify(x<<1,l,r,idx),modify(x<<1|1,l,r,idx);
}
if(rt[x].l==rt[x].r)
{
if(calc(mid,rt[x].idx)>calc(mid,idx))rt[x].idx=idx;
return ;
}
if(l<=mid)modify(x<<1,l,r,idx);
if(r>mid)modify(x<<1|1,l,r,idx);
}

复杂度

综上,斜率优化写的李超树只是李超线段树的一种特殊情况(每条直线的端点就都是整个区间的左右端点)。
我们在写普通李超线段树的插入操作的时候,把区间分割成一个个能被完全包含的小区间的复杂度是 O(logn) 的,然后对于每一个这样的区间,我们还要分别对其进行一次 O(logn) 的更新,所以总的复杂度是 O(log2n) 的,而询问的就是对于所在的所有区间的最大值/最小值取并集,所以就是 O(logn) 的。
插入:O(log2n)
查询:O(logn)

posted @   Hanggoash  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
动态线条
动态线条end
点击右上角即可分享
微信分享提示