李超线段树学习笔记 [模板]

  • 李 超 线 段 树 的 作 用 李超线段树的作用 线

用来处理多个有 斜率截距 的线段在区间上的 极值问题 .

  • 李 超 线 段 树 的 内 容 李超线段树的内容 线

普通线段树的节点一般直接保存区间和, 极值等信息,

李超线段树的节点保存过这个 区间中点最优 的直线, 注意是 区间中点最优,

意思就是: 查询 x x x 点的最优值时, 必须递归到底部叶子节点, 才可以获取 “单点 x x x 过哪个线段才能获得最优值” 的信息 .


  • 李 超 线 段 树 的 实 现 李超线段树的实现 线

插 入 节 点 ↓ 插入节点 ↓

将算法用 文字 加 分支结构 描述如下 ↓ ↓

  • 新加入的线段斜率大于原来线段斜率
    • 新线段在右区间完全优于原有线段, 将原有线段贬斥到左子树, 原有线段只可能在左子树优于新线段
    • 否则只有更右边有替换原线段的希望, 递归右区间 .
  • 新加入的线段斜率小于等于原来线段斜率
    • 新线段在做区间完全优于原有线段, 将原有线段贬斥到右子树, 原有线段只可能在右子树优于新线段
    • 否则只有更左边有替换原线段的希望, 递归左区间 .

总 体 来 说 总体来说 : 插入节点 相 当 于 拿 一 个 线 段 不 断 相当于拿一个线段不断 线 , 找 到 能 够 顶 替 的 线 段 就 顶 替 , 否 则 继 续 向 下 深 入 尝 试 . 找到能够顶替的线段就顶替, 否则继续向下深入尝试 . 线,.

void Modify(int k, int l, int r, int x){
	T[k].l = l, T[k].r = r;
        if(l == r){
                if(get_val(x, l) > get_val(T[k].xd, l)) T[k].xd = x;
                return ;
        }
        int mid = l+r >> 1;
        if(slop[T[k].xd] < slop[x]){ // 新加入的线段斜率大于原来线段斜率
                if(get_val(x, mid) > get_val(T[k].xd, mid)){ // 新线段在右区间完全优于原有线段
                        Modify(k<<1, l, mid, T[k].xd);       // 将原有线段贬斥到左子树, 原有线段只可能在右子树优于新线段
                        T[k].xd = x;
                }else   Modify(k<<1|1, mid+1, r, x);         // 否则只有更右边有替换原线段的希望
        }else{ //新加入的线段斜率小于等于原来线段斜率
                if(get_val(x, mid) > get_val(T[k].xd, mid)){ // 新线段在做区间完全优于原有线段
                        Modify(k<<1|1, mid+1, r, T[k].xd);   // 将原有线段贬斥到右子树, 原有线段只可能在右子树优于新线段
                        T[k].xd = x;
                }else   Modify(k<<1, l, mid, x);             // 否则只有更左边有替换原线段的希望
        }
}
单 点 查 询 ↓ 单点查询 ↓
double Query(int k, int x){
	int l = T[k].l, r = T[k].r;
        if(l == r) return get_val(T[k].xd, x);
        int mid = l+r >> 1;
        if(x <= mid) return std::max(get_val(T[k].xd, x), Query(k<<1, x));
        return std::max(get_val(T[k].xd, x), Query(k<<1|1, x));
}

  • 李 超 线 段 树 的 应 用 李超线段树的应用 线

例 题 1 : 例题1: 1: [JSOI2008]Blue Mary开公司

上方代码拼凑起来即为这道题 .

#include<bits/stdc++.h>

const int maxn = 50004;

int N;
int cnt;
double slop[maxn<<1];
double b[maxn<<1];

struct Node{ int l, r, xd; } T[maxn<<2];

double get_val(int cnt, int x){ return slop[cnt]*(x-1) + b[cnt]; }

void Modify(int k, int l, int r, int x){
	T[k].l = l, T[k].r = r;
        if(l == r){
                if(get_val(x, l) > get_val(T[k].xd, l)) T[k].xd = x;
                return ;
        }
        int mid = l+r >> 1;
        if(slop[T[k].xd] < slop[x]){ // 新加入的线段斜率大于原来线段斜率
                if(get_val(x, mid) > get_val(T[k].xd, mid)){ // 新线段在右区间完全优于原有线段
                        Modify(k<<1, l, mid, T[k].xd);       // 将原有线段贬斥到左子树, 原有线段只可能在右子树优于新线段
                        T[k].xd = x;
                }else   Modify(k<<1|1, mid+1, r, x);         // 否则只有更右边有替换原线段的希望
        }else{ //新加入的线段斜率小于等于原来线段斜率
                if(get_val(x, mid) > get_val(T[k].xd, mid)){ // 新线段在做区间完全优于原有线段
                        Modify(k<<1|1, mid+1, r, T[k].xd);   // 将原有线段贬斥到右子树, 原有线段只可能在右子树优于新线段
                        T[k].xd = x;
                }else   Modify(k<<1, l, mid, x);             // 否则只有更左边有替换原线段的希望
        }
}

double Query(int k, int x){
	int l = T[k].l, r = T[k].r;
        if(l == r) return get_val(T[k].xd, x);
        int mid = l+r >> 1;
        if(x <= mid) return std::max(get_val(T[k].xd, x), Query(k<<1, x));
        return std::max(get_val(T[k].xd, x), Query(k<<1|1, x));
}

int main(){
        scanf("%d", &N);
        while(N --){
                char opt[5];
                scanf("%s", opt);
                if(opt[0] == 'P'){
                        cnt ++;
                        scanf("%lf%lf", &b[cnt], &slop[cnt]);
                        Modify(1, 1, maxn, cnt);
                }else{
                        int x;
                        scanf("%d", &x);
                        printf("%d\n", (int)Query(1, x)/100);
                }
        }
        return 0;
}
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值