首页 > 其他分享 >李超线段树

李超线段树

时间:2024-10-20 21:53:08浏览次数:3  
标签:直线 int 线段 tr 李超 mid

李超线段树

最基础的李超线段树可以做下面的问题:

每次插入若干条直线 \(y=k_ix+b_i\),查询某个位置 \(x_i\) 上的最值。

考虑一棵线段树结构,在每个节点维护在当前区间中点上的最优直线,当插入一条新直线时:

  • 如果该节点为空就把新直线存到当前节点并返回。

  • 否则如果新直线在中点处取值比原本的最优直线更优就交换。

  • 如果新直线在左端点比原本直线有就递归左区间,右区间同理。

正确性证明:首先第二条保证了新直线在中点位置比原本的最优直线劣,那么如果在左端点也更劣,显然整个左区间都更劣,因此该直线没有用。

  • 查询时从询问的点每次往上跳,查询经过的所有直线的最大值即可。

具体实现时可以动态开点,时间复杂度 \(\Theta(n\log n)\),空间复杂度 \(\Theta(n)\)。

这是一个简洁的写法:

struct segment
{
    LL K,B;
    int p;
    LL operator ()(LL x){return K*x+B;}
}tr[N];
int idx=0;
void Ins(int &k,int l,int r,segment L)
{
    if(!k)
    {
        k=++idx;
        tr[k]=L;
        return;
    }
    int mid=(l+r)>>1;
    if(L(mid)>tr[k](mid))swap(L,tr[k]);
    if(L(l)>tr[k](l))Ins(ls[k],l,mid,L);
    if(L(r)>tr[k](r))Ins(rs[k],mid+1,r,L);
}
pair<LL,int> ask(int k,int l,int r,int x)
{
    if(!k)return make_pair(0,0);
    pair<LL,int> res=make_pair(tr[k](x),tr[k].p);
    int mid=(l+r)>>1;
    if(x<=mid)res=max(res,ask(ls[k],l,mid,x));
    else res=max(res,ask(rs[k],mid+1,r,x));
    return res;
}

[模板]李超线段树/[HEOI2013]Segment

插入的从直线变成了线段,把线段拆成 $\log $ 个区间内的直线即可,复杂度 \(\Theta(n\log^2n)\)。

应用

李超线段树最常用的就是解决斜率优化 dp,通常码量小细节少,除了部分卡 \(\log\) 的题,其他情况绝对是第一选择,可以替代大部分 CDQ 优化斜率优化 dp。

「CEOI2017」Building Bridges

可以写出简单的斜率优化式子,可以直接转化成插入直线、查询单点最值,比 CDQ 不知道好写到哪去了。

「SDOI2012」基站建设

道理差不多。

撤销

李超线段树不支持删除,但是显然支持 \(\Theta(\log)\) 的撤销。

CF678F Lena and Queries

除了删除之外和模板一样,套一层线段树分治就可以转化成插入和撤销了。

复杂度 \(\Theta(n\log ^2n)\)。

[CEOI 2009] Harbingers

一样的可以写成斜率优化式子,只不过是从祖先转移的。

在树上 dfs,李超树维护直线,回溯的时候撤销就行了。

广义李超线段树

注意到其实我们没有用到直线的很多性质,因此可以维护的不仅仅是直线,事实上只要该函数满足任意两个函数最多只有一个平凡交点即可。

「POI2011 R1」避雷针 Lightning Conductor

把 \(a_j+\sqrt{i-j}\) 看成函数用李超树维护即可。

可持久化李超线段树

类似普通线段树可持久化就行。

李超线段树合并

类似普通线段树合并,只不过每次要把一个线段树节点的直线插到另一个线段树里。

void Ins(int &k,int l,int r,segment L)
{
    if(!k)
    {
        k=++tot;
        seg[k]=L;
        return;
    }
    pushdown(k);
    int mid=(l+r)>>1;
    if(L(mid)<seg[k](mid))swap(L,seg[k]);
    if(L(l)<seg[k](l))Ins(lson[k],l,mid,L);
    else if(L(r)<seg[k](r))Ins(rson[k],mid+1,r,L);
}
int Merge(int x,int y,int l,int r)
{
    if(!x||!y)return x+y;
    pushdown(x);pushdown(y);
    Ins(x,l,r,seg[y]);
    int mid=(l+r)>>1;
    lson[x]=Merge(lson[x],lson[y],l,mid);
    rson[x]=Merge(rson[x],rson[y],mid+1,r);
    return x;
}

正确性没什么好说的,复杂度据说是 1 个 log,不是很懂。

CF932F. Escape Through Leaf

别的练习题

CF1303G Sum of Prefix Sums

标签:直线,int,线段,tr,李超,mid
From: https://www.cnblogs.com/jesoyizexry/p/18487975

相关文章

  • 线段树分治学习笔记
    前置知识:线段树(只需要了解其结构)支持撤销的数据结构,如可撤销并查集,可持久化数据结构等。线段树分治是什么一种离线算法,用于处理假如某些信息会在某个时间段出现,求某个时刻的信息并。常见的离线算法还有CDQ分治,考虑一下这两个算法的区别。CDQ分治:对于每个操作,考虑其对后面询......
  • 【算法】李超线段树
    1.算法简介李超线段树是用来维护一次函数的线段树,可以支持插入线段(一次函数),查询直线\(x=k\)的与区间内线段交点纵坐标的最值等操作。考虑如何使用线段树维护线段。可以利用标记永久化的思想,对于线段树内每一个节点存储所有在当前区间\([l,r]\)中,\(f(mid)\)最大/最小的一......
  • 012集——CAD图中线段坐标导出到txt(CAD—C#二次开发入门)
    如图所示,CAD图中line和pline坐标和图层数据导出到txt文本。 程序运行后导出如下文件:附部分源代码:publicstaticvoidDwgToTxt(thisDatabasedb){//vardb=Z.db;vared=Z.ed;//Point3dpt;BlockDatadata=newBlockData();List<Bloc......
  • luogu P3842 [TJOI2007] 线段
    link好题,考虑如何设定状态。设\(dp_{i,0/1}\)表示到了第\(i\)行走完后停在这一行的最左侧/最右侧。设定\(l_i\)表示这一行该线段的最左侧,\(r_i\)表示这一行的最右侧。思考如何转移。1.当我处在这一行的最左侧时,我需要从这一行的右端点转移过来,所以你的贡献要加上这个线段的长......
  • P10009 [集训队互测 2022] 线段树
    我们先考虑全局操作的影响。我们对每个位置考虑前面位置对它的贡献,根据差分序列的性质,当你做了\(k\)次异或差分,可以看作每次每个位置贡献给下一行的这一个位置和右侧一个位置,即\(c_{i,j}\toc_{i+1,j},c_{i+1,j+1}\),这个东西显然和杨辉三角等价,贡献方式可以视作每次向下一行......
  • 线段树合并
    线段树合并,顾名思义,就是将两个线段树合并在一起(这里的线段树大多是动态开点的权值线段树)首先线段树合并就是把一大堆权值线段树合并起来的算法实现流程就是,同时递归的遍历两个要合并的线段树\(A,B\),有如下几种情况:1.现在在合并区间\(2,4\)对应的节点,\(A\)有而\(B\)没......
  • 线段树
    不带lazy#include<bits/stdc++.h>usingnamespacestd;#definelllonglonglltr[1000000],a[1000000],ans[1000000],lazy[1000000];voidbui(llid,lll,llr){ if(l==r){ tr[id]=a[l]; return; } llmid=(l+r)>>1; bui(id*2,l,mid); bui(id*2+1,mi......
  • 计蒜客:斑点蛇(线段树)
     样例输入 1012345678910Query13Add36Query27Sub102Add63Query310End  样例输出 63359采用标准模板即可。注意线段树的节点个数一般为其范围的4倍。1#include<bits/stdc++.h>2usingnamespacestd;3vector<int>s(5000......
  • 【分治】线段树 SegmentTree
    算法描述线段树是一种能够处理区间修改和区间查询的数据结构。顾名思义,线段树就是一种存储着线段数据的树形结构。它的每个节点都表示一个线段区间,每个节点的孩子节点存储的就是该区间的左半段和右半段。每个线段区间都存储着一个值,一般是区间和,也有可能是区间最大/最小值。......
  • 线段树(超详解)
    线段树(超详解)Author:铜陵一中缪语博在网上看了几个讲线段树的,都感觉不咋地,自己琢磨了几天,大致弄明白了。于是趁兴写了一篇关于线段树的文章,希望拯救那些看oi−......