李超线段树

李超线段树

概念

李超线段树是巨佬李超发明的一种可以求函数定点最值的线段树,又名李超树。代码简短,思想简明,用途广泛。

问题

李超线段树是用来解决类似于这种问题 题目传送门

要求在平面直角坐标系下维护两个操作:

  1. 在平面上加入一条线段。记第 i i i 条被插入的线段的标号为 i i i
  2. 给定一个数 k k k,询问与直线 x = k x = k x=k 相交的线段中,交点纵坐标最大的线段的编号。

思路

李超线段树的结构和普通线段树一样的,只是它每个节点存的是该区间优势最大的线段

区间 [ L , R ] [L,R] [L,R] 中,蓝色折线为最高折线,绿色线段为该区间的优势最大线段

插入操作

对于一个区间,它被线段覆盖的情况可以分为六种:

1、线段覆盖的区间和该区间不相交,直接返回

2、线段覆盖部分该区间,递归到左右子区间继续处理;

3、线段完全覆盖该区间: 线段在两个端点处值均比之前保存的优势线段更大,则替换优势线段,返回;

4、线段在两个端点处的值均比之前的保存的优势线段小,则返回 5、线段在两个端点处与之前保存的优势线段比较,如果在中点处更优,则更新优势线段(交换两 线段);

6、然后再判断左右端点处的值,如果该侧优势线段不占优势,则递归该侧。

查询

它维护的是区间中点处的最大(最小)值的线段,采用 标记永久化。 所谓标记永久化是指标记不下传,查询时,需要由该节点及其所有祖先的标记综合起来才能得出答案。

因为李超树每个区间保存的只是当前区间的中点的最大值,所以它的标记是不能下传的,下传了反而不 准确。

每个区间保存的只是区间 处占优势的线段的编号。(另有一个线段的数组,记录了每条线段的 斜率和截距)。优势线段仅仅只是中点更优,并不是处处占优,也不是端点占优。

适合 单点查询,查询时必须要将叶节点的所有祖先的优势线段在该处进行比较。

例题

[P4097 【模板】李超线段树 / HEOI2013] Segment - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

版题。 可以感性理解一下

#include <bits/stdc++.h>
#define fu(x , y , z) for(int x = y ; x <= z ; x ++)
#define lp p<<1
#define rp p<<1|1
using namespace std;
const int N = 1e5 + 5 , mod = 39989 , my = 1000000000;
const double eps = 1e-8;
int l[N << 3] , r[N << 3] , tr[N << 3] , tot;
double k[N] , b[N];
inline int dcmp(double x) {
    return fabs(x) <= eps ? 0 : x < 0 ? -1 : 1;
    // fabs (x) <= eps 
}
double f (int x , int p) { return 1.0 * k[x] * p + b[x]; }
bool pd (int x , int y , int p) {
    double fx = f(x , p) , fy = f (y , p);
    return fabs (fy - fx) >= eps ? fx < fy : x > y;
    // return dcmp(fx-fy) ? fx < fy : x > y;
}
void build (int p , int ll , int rr) {
    l[p] = ll , r[p] = rr;
    if (ll == rr) return;
    int mid = (ll + rr) >> 1;
    build (lp , ll , mid);
    build (rp , mid + 1 , rr);
}
void change (int p , int ll , int rr , int x) {
    if (r[p] < ll || rr < l[p]) return;
    if (ll <= l[p] && r[p] <= rr) {
        if (pd (x , tr[p] , l[p]) && pd (x , tr[p] , r[p])) return;
        if (pd (tr[p] , x , l[p]) && pd (tr[p] , x , r[p])) {
            tr[p] = x;
            return;
        }
        int mid = (l[p] + r[p]) >> 1;
        if (pd (tr[p] , x , mid)) swap (tr[p] , x);
        if (pd (tr[p] , x , l[p])) change (lp , l[p] , r[p] , x);
        else change (rp , l[p] , r[p] , x);
        return;
    }
    change (lp , ll , rr , x) , change (rp , ll , rr , x);
}
int query (int p , int x) {
    if (x < l[p] || r[p] < x) return 0;
    if (l[p] == r[p] && l[p] == x) return tr[p];
    int mid = (l[p] + r[p]) >> 1 , res = 0;
    if (x <= mid) res = query (lp , x);
    else res = query (rp , x);
    // res = x <= mid ? query(lp,x) : query(rp,x);
    if (pd (res , tr[p] , x)) res = tr[p];
    return res;
}
int main () {
    int T;
    scanf ("%d" , &T);
    int op , x , lst = -1 , y , xx , yy;
    build (1 , 1 , 40000);
    while (T --) {
        scanf ("%d" , &op);
        if (!op) {
            scanf ("%d" , &x);
            x = (x + lst + mod) % mod + 1;
            // cout << x << "\n";
            lst = query (1 , x);
            printf ("%d\n" , lst);
            lst --;
            // if (lst) lst --;
        }
        else {
            scanf ("%d%d%d%d" , &x , &y , &xx , &yy);
            x = (x + lst + mod) % mod + 1 , xx = (xx + lst + mod) % mod + 1;
            y = (1ll * y + lst + my) % my + 1 , yy = (1ll * yy + lst + my) % my + 1;
            if (xx < x) swap (xx , x) , swap (yy , y);
            tot++;
            if (x == xx) k[tot] = 0 , b[tot] = max (y , yy);
            else k[tot] = (double)(yy - y) / (xx - x) , b[tot] = yy - k[tot] * xx;
            change (1 , x , xx , tot);  
        }
    }
    return 0;
}
// 785

一般的斜率优化也可以用李超线段树来写

  • 4
    点赞
  • 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、付费专栏及课程。

余额充值