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


    • 线李超线段树的作用

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

    • 线李超线段树的内容

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

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

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


    • 线李超线段树的实现

    插入节点 ↓

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

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

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

    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: [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
    ", (int)Query(1, x)/100);
                    }
            }
            return 0;
    }
    
  • 相关阅读:
    机器学习入门-贝叶斯垃圾邮件过滤(原理)
    机器学习入门-贝叶斯拼写纠错实例
    机器学习入门-贝叶斯算法(原理)
    机器学习入门-集成算法(bagging, boosting, stacking)
    高并发网站技术架构
    Nginx教程
    Shell脚本部分语法
    关于文本处理sort-cut-wc详解
    vim操作命令
    修改Linux基本配置
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822540.html
Copyright © 2020-2023  润新知