首页 > 其他分享 >【学习笔记】李超线段树

【学习笔记】李超线段树

时间:2023-07-09 19:11:17浏览次数:40  
标签:处点值 return int 线段 db 李超 笔记 区间

维护一次函数

模板题 为例。

使用线段树维护线段,每个节点维护的都是完全覆盖这个区间的线段。

考虑当前节点已经有线段 \(f\),现在加入线段 \(g\)。

暴力想法是暴力递归每个子区间,把更优的保留,注意到 \(f,g\) 最多一个交点,因此也最多一侧的子区间需要暴力递归。

具体流程如下:

先比较 \(mid\) 处点值,钦定 \(f\) 为 \(mid\) 处点值不劣的线段。

  • 若 \(l\) 处点值 \(g\) 更优,说明交点在左区间,那么右区间更优的仍为 \(f\),左区间递归处理。

  • 若 \(r\) 处点值 \(g\) 更优,说明交点在右区间,那么左区间更优的仍未 \(g\),右区间递归处理。

  • 特别地,若 \(l\) 或 \(r\) 处点值相等,且新增加的线段在 \(mid\) 处点值更优,那么就递归处理对应的区间。

  • 处理之后保留在当前节点的线段应当为 \(f\),即 \(mid\) 处点值不劣的线段。

这样类似于标记永久化,查询时递归每个区间,总复杂度 \(O(n\log^2 n)\)。(如果添加直线就是 \(O(n\log n)\)。)

点击查看代码
int n,X=39989,Y=1000000000;

struct Line{
    db k,b;
    Line()=default;
    Line(db k_,db b_):k(k_),b(b_){}
}L[maxn];
int tot;

inline db get_y(int id,int x){
    if(!id) return 0;
    return L[id].k*x+L[id].b;
}
inline int check(int id1,int id2,int x){
    db y1=get_y(id1,x),y2=get_y(id2,x);
    if(y1-y2>eps) return 1;
    else if(y2-y1>eps) return -1;
    else return 0;
}
inline pdi max(pdi A,pdi B){
    if(A.fir-B.fir>eps) return A;
    else if(B.fir-A.fir>eps) return B;
    else{
        if(A.sec<B.sec) return A;
        else return B;
    }
}
struct SegmentTree{
#define mid ((l+r)>>1)
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
    int tag[maxn<<2];
    void update(int rt,int l,int r,int id){
        if(!tag[rt]) return tag[rt]=id,void();
        if(check(id,tag[rt],mid)==1) swap(tag[rt],id);
        int chkl=check(id,tag[rt],l),chkr=check(id,tag[rt],r);
        if(chkl==1||(!chkl&&id<tag[rt])) update(lson,id);
        if(chkr==1||(!chkr&&id<tag[rt])) update(rson,id);
    }
    void insert(int rt,int l,int r,int pl,int pr,int id){
        if(pl<=l&&r<=pr){
            update(rt,l,r,id);
            return;
        }
        if(pl<=mid) insert(lson,pl,pr,id);
        if(pr>mid) insert(rson,pl,pr,id);
    }
    pdi query(int rt,int l,int r,int x){
        db y=get_y(tag[rt],x);
        pdi res=make_pair(y,tag[rt]);
        if(l==r) return res;
        if(x<=mid) res=max(res,query(lson,x));
        else res=max(res,query(rson,x));
        return res;
    }
#undef mid
#undef lson
#undef rson
}S;

int lastans;

int main(){
    n=read();
    while(n--){
        int opt=read();
        if(opt==1){
            int x0=read(),y0=read(),x1=read(),y1=read();
            x0=(x0+lastans-1)%X+1,y0=(y0+lastans-1)%Y+1,x1=(x1+lastans-1)%X+1,y1=(y1+lastans-1)%Y+1;
            if(x0>x1) swap(x0,x1),swap(y0,y1);
            if(x0==x1) L[++tot]=Line(0,max(y0,y1));
            else{
                db k=1.0*(y1-y0)/(x1-x0),b=y0-k*x0;
                L[++tot]=Line(k,b);
            }
            S.insert(1,1,X,x0,x1,tot);
        }
        else{
            int x=read();
            x=(x+lastans-1)%X+1;
            lastans=S.query(1,1,X,x).sec;
            printf("%d\n",lastans);
        }
    }
    return 0;
}

斜率优化 DP

斜率优化 DP 中,通常写成 \(y=kx+b\) 的形式,其中 \(y,x\) 均与决策点 \(j\) 有关,通常是使用数据结构维护凸包。

在 \(x\) 具有单调性的前提下,\(k\) 具有单调性的情况,可以单调队列维护;反之可以单调栈维护并二分。

当 \(x\) 不具有单调性时,就需要用到李超线段树。

直接抛弃前面对凸包的依赖,我们所要找的实际上过 \((x_j,y_j)\) 的且斜率为 \(k\) 直线中,截距满足最值要求的一个。直接移项成 \(b=-x_j\times x+y_j\),这样就是把 \(x=k\) 代入求最值了,可以李超线段树维护。

因此李超线段树可以解决没有任何单调性的斜率优化。

例题

Luogu-P4254 JSOI2008 Blue Mary 开公司

维护一次函数模板。

Luogu-P2497 SDOI2012 基站建设

运用几何知识可以得到:\(\sqrt{r_i'}=\dfrac{x_i-x_j}{2\sqrt{r_j}}\)。

转移方程:

\[f_i=v_i+\min_{j=1}^{i-1} f_j+\dfrac{x_i-x_j}{2\sqrt{r_j}} \]

移项后意识到 \(X_j=-\dfrac{1}{2\sqrt{r_j}},Y_j=f_j-\dfrac{X_j}{2\sqrt{r_j}}\),李超线段树维护。(离散化或动态开点均可)

参考资料

标签:处点值,return,int,线段,db,李超,笔记,区间
From: https://www.cnblogs.com/SoyTony/p/Learning_Notes_about_Li-Chao_Segment_Tree.html

相关文章

  • Cesium学习笔记3——加载地图服务
    申请成为天地图开发者,创建应用 编写代码:<!DOCTYPEhtml><htmllang="en"><head><!--Usecorrectcharacterset.--><metacharset="utf-8"/><!--TellIEtousethelatest,bestversion.--><......
  • 数学分析学习笔记
    序言数学分析原理1、叙述上的系统性和可能范围内的严格性叙述按照逻辑的顺序2、数学分析是行动的指南做习题和例题的重要性3、数学分析与其它应用领域的联系4、分析计算一直算到求出数字的结果,学生要熟悉近似方法的运用与学会作出近似公式5、......
  • 系统架构设计师笔记第30期:机器人技术
    机器人技术是一门涵盖多学科的领域,旨在设计、构建和开发能够模仿、辅助或替代人类在特定任务或活动中执行的自动化机器人系统。机器人技术结合了机械工程、电子工程、计算机科学、人工智能等多个领域的知识和技术。机器人技术的目标是开发能够感知环境、理解任务、执行动作并与人类......
  • abc309f <线段树 + 离散化 + 双指针>
    F-BoxinBox//https://atcoder.jp/contests/abc309/tasks/abc309_f//<线段树+离散化+双指针>[unique+lower_bound+erase+lambda+vector]//总体思路:将每个三元组记录为如a[3]的3维向量,依次考虑每个向量,检查是否存在一个向量完全比它'小'//将向量按......
  • [笔记]组成原理_指令系统_指令的寻址方式(题)
    指令系统中采用不同寻址方式的目的是()A.提供扩展操作码的可能,并降低指令译码难度。B.可缩短指令字长扩大寻址空间,提高编程的灵活性.C.实现程序控制.D.三者都正确.采用不同寻址方式提高了指令译码的复杂度,所以A错。实现程序控制是通过转移指令而非寻址方式进行的,与寻址方式无......
  • 计算机网络自顶而下第一章笔记记录
    计算机网络节点主机及其上运行的应用程序(能接入互联网的任何终端)(端点)路由器,交换机等网络交换设备。(其中,路由器与交换机的工作层次不同,路由器在网络层工作,交换机在链路层工作)边 通信链路(按接入设备的不同)接入网链路,主机连接到互联网的链路(只要有端点即可)主干链路:路由器......
  • [PowerShell]设置笔记本亮度 -- CIM cmdlet
    如下:$monitor=Get-CimInstance-Namespaceroot/WMI-ClassNameWmiMonitorBrightnessMethodsInvoke-CimMethod-InputObject$monitor-MethodNamewmisetBrightness-Arguments@{Timeout='10';Brightness='25'}参考https://learn.microsoft.com......
  • [学习笔记] 启发式合并 & DSU on Tree
    一、启发式合并启发式合并多用于合并两个集合,现在有这样一个问题:现在给定\(n\)个集合,第\(i\)个集合初始只有\(\{i\}\),要支持集合的合并操作。如果我们暴力合并,时间复杂度会是\(O(n^2)\)的。参考并查集的按秩合并,考虑将小的集合合并到大的集合上。考虑计算时间复杂度,容......
  • 转载-ZC706应用笔记
    转载-ZC706应用笔记2020-01-0322:36:351、板载时钟配置。ZC706有200MHzLVDS差分时钟源SiT9102,作为ZYNQ系统参考时钟。 COMMS5板子上有ADCLK846时钟Buffer分路器作为AD9361的时钟源,AD846双路输出,分别作为两个AD9361的单端时钟源。ADCLK846的输入是1.8V有源晶振40MH......
  • python笔记1.2
    基本输入函数input的应用name=input('请输入您的姓名')print('您的姓名为:'+name)num=int(input('请输入您的幸运数字'))#print('您的幸运数字为:'+num)#字符串和整数无法运算print('您的幸运数字为:',num)#正常返回num单行注释#正常返回num多行注释'''版权所有......