首页 > 其他分享 >【数据结构】【模板】李超线段树

【数据结构】【模板】李超线段树

时间:2024-08-28 09:06:18浏览次数:8  
标签:数据结构 线段 李超 mid y1 x2 x1 id 模板

李超线段树

定义

可以看看洛谷的模板题目:

image

作用

  1. 优化动态规划,如果可以将一个动态规划的转移式子转化为 \(y = kx + b\) 的形式,那么我们可以边转移边将 \(y = kx + b\) 这条线段放入李超线段树,然后在下次转移时,直接调用下次计算出来的 \(x\) 位置上的最大值或最小值。(结合题目理解)

构建方式

以洛谷模板题为例。

插入线段

对于线段树上的区间 \([l, r]\),保存一个线段编号,定义 \(p(x)\) 表示线段 \(p\) 在横坐标为 \(x\) 时的纵坐标。

当有新的线段来时,以以下方式更新。

  1. 取区间 \([l, r]\) 的中点 \(mid\)。
  2. 看看将 \(mid\) 作为横坐标时,保存的线段 \(id\) 和新来的线段 \(seg\) 谁大,如果 \(seg(mid)\) 比 \(id(mid)\) 大,那么交换 \(id\) 和 \(seg\),这时 \(id(mid) < seg(mid)\)。
  3. 接下来我们看看 \(id\) 这条线段是否还有可能成为左右区间的代表线段,看看做左端点谁大,如果 \(id(l)\) 比 \(seg(l)\) 更大,那么递归更新区间 \([l, mid]\),线段为 \(id\)。
    image
  4. 然后再看看右区间,如果 \(id(r)\) 比 \(seg(r)\) 更大,那么递归更新区间 \([mid + 1, r]\),线段为 \(id\)。
    image

因为 3. 4 中的条件只有一种可能实现,这也说明了:

  1. 只有一种情况会往下递归;
  2. 不能用 pushdown;
  3. 时间复杂度为 \(O(\log^2 n)\)。

查询线段

我们可以按照线段树区间查询的顺序,从上往下按照取出的线段,比较其在横坐标为 \(x\) 的大小。

模板代码

P4097

#include <bits/stdc++.h>

using namespace std;

const int N = 100010;
const double eps = 1e-6;

int cmp(double x, double y) {
    if (fabs(x - y) < eps) return 0;
    if (x < y) return -1;
    return 1;
}

struct node {
    int id;
} tr[N << 2];

double gety(double k, int x, double b) {
    return k * x + b;
}

double k[N], b[N];

bool compare(int v1, int v2, int x) {
    double y1 = gety(k[v1], x, b[v1]);
    double y2 = gety(k[v2], x, b[v2]);
    if (!cmp(y1, y2)) return v1 < v2;
    return cmp(y1, y2) == 1;
}

void update(int u, int l, int r, int pl, int pr, int x) {
    int mid = l + r >> 1;
    if (pl <= l && r <= pr) {
        if (!tr[u].id) {
            tr[u].id = x;
            return;
        }
        if (compare(x, tr[u].id, mid)) swap(tr[u].id, x);
        if (compare(x, tr[u].id, l)) update(u << 1, l, mid, pl, pr, x);
        if (compare(x, tr[u].id, r)) update(u << 1 | 1, mid + 1, r, pl, pr, x);
        return;
    }
    if (pl <= mid) update(u << 1, l, mid, pl, pr, x);
    if (pr > mid) update(u << 1 | 1, mid + 1, r, pl, pr, x);
}

int query(int u, int l, int r, int x) {
    if (l == r) return tr[u].id;
    int mid = l + r >> 1;
    int ans = tr[u].id;
    if (x <= mid) {
        int ans2 = query(u << 1, l, mid, x);
        if (compare(ans, ans2, x)) return ans;
        else return ans2;
    }
    else {
        int ans2 = query(u << 1 | 1, mid + 1, r, x);
        if (compare(ans, ans2, x)) return ans;
        else return ans2;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int q;
    cin >> q;
    int opt, x1, y1, x2, y2, lastans = 0, cnt = 0;
    for (int i = 1; i <= q; i++) {
        cin >> opt;
        if (opt == 0) {
            cin >> x1;
            x1 = (x1 + lastans - 1) % 39989 + 1;
            cout << (lastans = query(1, 1, 40000, x1)) << '\n';
        }
        else {
            cin >> x1 >> y1 >> x2 >> y2;
            x1 = (x1 + lastans - 1) % 39989 + 1;
            x2 = (x2 + lastans - 1) % 39989 + 1;
            y1 = (y1 + lastans - 1) % 1000000000 + 1;
            y2 = (y2 + lastans - 1) % 1000000000 + 1;

            if (x1 > x2) swap(x1, x2), swap(y1, y2);
            cnt++;
            if (x1 == x2) b[cnt] = max(y1, y2);
            else {
                k[cnt] = 1.0 * (y1 - y2) / (x1 - x2);
                b[cnt] = y1 - k[cnt] * x1;
            }
            update(1, 1, 40000, x1, x2, cnt);
        }
    }
    return 0;
}

例题

标签:数据结构,线段,李超,mid,y1,x2,x1,id,模板
From: https://www.cnblogs.com/Yuan-Jiawei/p/18383898

相关文章

  • 考研系列-408真题数据结构篇(10-17)
    写在前面此文章是本人在备考过程中408真题数据结构部分(2010年-2017年)的易错题及相应的知识点整理,后期复习也尝尝用到,对于知识提炼归纳理解起到了很大的作用,分享出来希望帮助到大家~#2010年1.散列表处理冲突的方法......
  • 【数据结构】关于二叉搜索树,你知道如何实现增删模拟吗???(超详解)
    前言:......
  • 数据结构链表(C语言版)
    链表定义链表是一种常见的基础数据结构,它由一系列节点(Node)组成,每个节点包含数据域和指向列表中下一个节点的指针(在双向链表中还会有指向前一个节点的指针)。链表的一个优点是它允许有效地在序列中插入和删除元素。节点(Node)一个节点通常包含两个部分:数据域(DataField):存储实......
  • 数据结构:顺序表
    目录结构体顺序表存储数据类型结构体 顺序表结构体函数 初始化顺序表判断顺序表是否存满判断顺序表是否为空顺序表插入新元素在指定位置插入新元素遍历顺序表所有元素,对每个元素完成指定操作   (指定操作1) 打印所有元素    (指定操作2)更新指定元素......
  • Java数据结构栏目总结
     目录数组与稀疏数组队列:自己用数组模拟Queue环形队列,取模【取余】实现.单链表(LinkList)双向链表(Next、Pre)单向环形链表线性结构数组与稀疏数组稀疏数组,很多0值,可用于压缩特点:共n+1行3列,n为不同值的个数(0除外)第一行:数组的行数、列数、不同值的个数第二行:行......
  • 数据结构——顺序表
    数据结构顺序表基本概念顺序表:顺序存储的线性表。链式表:链式存储的线性表,简称链表。顺序存储就是将数据存储到一片连续的内存中,在C语言环境下,可以是具名的栈数组,或者是匿名的堆数组。存储方式不仅仅只是提供数据的存储空间,而是必须要能体现数据之间的逻辑关系。当采用......
  • 数据结构——链表
    单链表基本概念顺序表:顺序存储的线性表。链式表:链式存储的线性表,简称链表。既然顺序存储中的数据因为挤在一起而导致需要成片移动,那很容易想到的解决方案是将数据离散地存储在不同内存块中,然后在用来指针将它们串起来。这种朴素的思路所形成的链式线性表,就是所谓的链表......
  • 数据结构学习笔记
    李超线段树学习笔记模板传送门从模板题就能看出来嗷,李超线段树非常牛逼。\bx从名字中就能看出来嗷,这玩意儿是个线段树。那么考虑在线段树上维护一堆线(一次函数)。对于每个点,存所有线中,使这个线段$mid$的点的线。对于加入一个点,根节点递归,扫到一个点时,若这个点在$mid$......
  • D11 kubernetes yaml模板与示例
    》 kubernetes资源的创建、更新、删除等操作均可以使用json或者yaml文件进行操作,更新和删除可以依赖之前的文件进行更改。但是资源清单文件就没那么容易了,k8s的配置项实在是太多,稍微不注意就会犯错。要写好一个yaml文件,需要了解yaml文件的语法,需要整我k8s的各种配置。本文按照k8s......
  • 有趣的C++模板代码
    1#include<iostream>2template<typename...Ts>3structCNAny{4staticboolDo(inti){5return(Ts::Do(i)||...);6}7};89template<typename...Ts>10structCNAll{11staticboolDo(inti){......