李超线段树学习笔记

文章目录李超线段树介绍主要思想实现大量例题P4254 - [JSOI2008]Blue Mary开公司P4097 - [HEOI2013]SegmentP4069 - [SDOI2016]游戏李超线段树介绍  李超线段树作为一种高级数据结构,其最经典的应用就是维护二维平面直角坐标系中,支持动态插入线段,(不支持删除线段),询问已插入直线中与直线 x=x0x=x_0x=x0​ 相交 yyy 值最大/最小值。其中插入直线复杂度 O(nlogn)O(nlogn)O(nlogn),在指定区间插入线段复杂度 O
摘要由CSDN通过智能技术生成

李超线段树

介绍

  李超线段树作为一种高级数据结构,其最经典的应用就是维护二维平面直角坐标系中,支持动态插入线段,(不支持删除线段),询问已插入直线中与直线 x = x 0 x=x_0 x=x0 相交 y y y 值最大/最小值。其中插入直线复杂度 O ( n l o g n ) O(nlogn) O(nlogn),在指定区间插入线段复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)

主要思想

  对于上述问题,暴力做法显然就是 O ( n ) O(n) O(n) 的遍历所有已插入线段,比较交点的 y y y 值。这个做法复杂度的瓶颈在于我们的“最优解“集合过大,实际上有些线段根本不可能成为最优解,那么李超线段树正是运用这种缩小最优解集合的方法降低复杂度。

  首先,李超线段树中每个区间只记录在当前区间可能成为最优解的线段,即该线段在当前区间的某个取值上有最优解,我们称这样的线段为优势线段。如何维护区间内的优势线段就成了李超数的核心问题,我们将使用线段树的框架并且利用标记永久化这一方法,接着来具体分析这一问题:

我们以求最大值为例进行分析:

1.当区间内没有任何线段时:我们直接将线段放入当前区间即可

2.当区间内存在旧线段,且新线段的斜率大于旧线段的斜率时,设当前区间中点为 m i d mid mid

  • 如果新线段在中点的值大于旧线段,那么新线段在 [ m i d + 1 , R ] [mid+1,R] [mid+1,R] 上整体取值都比旧线段更优,我们直接用新线段替换旧线段,并且此时旧线段仍可能在 [ L , m i d ] [L,mid] [L,mid] 区间有优势,我们把旧线段下放至 [ L , m i d ] [L,mid] [L,mid] 区间即可
  • 如果新线段在中点的值小于旧线段,那么旧线段在 [ L , m i d ] [L,mid] [L,mid] 上整体取值一定都比旧线段更优, 而在 [ m i d + 1 , R ] [mid+1,R] [mid+1,R] 区间新线段仍可能存在优势,所以旧线段仍然是 [ L , R ] [L,R] [L,R] 的优势线段,所以我们保留旧线段,下放线段至 [ m i d + 1 , R ] [mid+1,R] [mid+1,R]

3.当区间内存在旧线段,且新线段的斜率小于旧线段的斜率时同上

4.当区间内存在旧线段,且新线段的斜率相同时,显然我们只需要保留截距更大的线段即可

5.上述过程已经可以很好的维护优势线段,但是在此之前我们可以先判断两条线段是否存在严格优势关系,如果存在我们可以直接排除另一条线段,这样我们在情况 2,3 时就可以保证下放的线段不是毫无用处的,相当于做一个小剪枝

可以发现上述过程中我们维护的所谓优势线段,并不是严格的,复杂度因此有了保障。但是我们在查询的时候显然不能只递归到一个叶子节点,我们必须在向下递归的同时计算经过的线段的最值,即利用标记永久化来得到最优解。

实现

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int maxn=1e6+10;
const int maxm=2e5+10;
const int p=998244353;

int k[maxm],b[maxm];
int tag0[maxn<<2],tag1[maxn<<2];
int n,m,tot=0;

inline ll cal(int i,int x){
   
    return 1ll*k[i]*x+b[i];
}

void modify_min(int l,int r,int x,int i){
   
    if(!tag0[x]){
   tag0[x]=i;return;}
    if(l==r){
   
        if(cal(tag0[x],l)>cal(i,l)) tag0[x]=i;
        return;
    }
    int mid=l+r>>1;
    ll y1=cal(tag0[x],mid),y2=cal(i,mid);
    if(k[tag0[x]]>k[i]){
   
        if(y1<=y2) modify_min(mid+1,r,x<<1|1,i);
        else modify_min(l,mid,x<<1,tag0[x]),tag0[x]=i;
    }
    else if(k[tag0[x]]<k[i]){
   
        if(y1<=y2) modify_min(l,mid,x<<1,i); 
        else modify_min(mid+1,r,x<<1|1,tag0[x]),tag0[x]=i;
    }
    else if(b[tag0[x]]>b[i]) tag0[x]=i;
}

void modify_max(int l,int r,int x,int i){
   
    if(!tag1[x]){
   tag1[x]=i;return;}
    if(l==r){
   
        if(cal(tag1[x],l)<cal(i,l)) tag1[x]=i;
        return;
    }
    int mid=l+r>>1;
    ll y1=cal(tag1[x],mid),y2=cal(i,mid);
    if(k[tag1[x]]>k[i]){
   
        if(y1<=y2) modify_max(mid+1,r,x<<1|1,tag1[x]),tag1[x]=i;
        else modify_max(l,mid,x<<1,i);
    }
    else if(k[tag1[x]]<k[i]){
   
        if(y1<=y2) modify_max(l,mid,x<<1,tag1[x]),tag1[x]=i;
        else modify_max(mid+1,r,x<<1|1,i);
    }
    else if(b[tag1[x]]<b[i]) tag1[x]=i;
}

ll query_min(int l,int r,int x,int pos){
   
    if(tag0[x]==0) return 1e18;
    if(l==r) return cal(tag0[x],pos);
    int mid=l+r>>1;
    ll ans=cal(tag0[x],pos);
    if(pos<=mid) return min(ans,query_min(l,mid,x<<1,pos));
    else return min(ans,query_min(mid+1,r,x<<1|1,pos));
}

ll query_max(int l,int r,int x,int pos){
   
    if(tag1[x]==0) return -1e18;
    if(l==r) return cal(tag1[x],pos);
    int mid=
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和提到,Linux下安装ffmpeg是非常方便的。下面给出在Linux上安装ffmpeg的步骤: 1. 首先,需要安装Cygwin。Cygwin是一个在Windows上运行类似于Linux的环境的工具。可以从官方网站上下载并安装。 2. 安装完Cygwin后,打开终端,输入以下命令下载x264源代码并进行编译: ``` wget http://mirror.yandex.ru/mirrors/ftp.videolan.org/x264/snapshots/last_x264.tar.bz2 bunzip2 last_x264.tar.bz2 tar -vxf last_x264.tar cd last_x264 ./configure --enable-static --enable-shared --disable-asm --disable-avs make && sudo make install ``` 3. 然后,从ffmpeg官网下载ffmpeg源代码,并进行编译。编译方法可以参考官方文档或者在终端中输入以下命令: ``` wget http://ffmpeg.org/releases/ffmpeg-[版本号].tar.gz tar -xzvf ffmpeg-[版本号].tar.gz cd ffmpeg-[版本号] ./configure --enable-shared make sudo make install ``` 其中,是你想要安装的ffmpeg的版本号。 4. 编译完成后,就可以使用ffmpeg了。可以通过在终端中输入`ffmpeg`命令来验证是否安装成功。 请注意,以上步骤仅适用于在Linux系统上安装ffmpeg。如果你是在其他操作系统上进行安装,请参考相关的文档或者教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Windows下编译安装 FFmpeg](https://blog.csdn.net/heng615975867/article/details/119821945)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值