李超线段树

李超线段树是一种用于维护平面直角坐标系内线段关系的数据结构。它常被用来处理这样一种形式的问题:给定一个平面直角坐标系,支持动态插入一条线段,询问从某一个位置 (X,+∞)(X,+\infty)(X,+∞) 向下看能看到的最高的一条线段(也就是给一条竖线,问这条竖线与所有线段的最高的交点


如上图,有三条线段,两条红色竖线代表两个询问,则点 AAA 与点 BBB 就是询问到的答案。
李超线段树的核心是维护每个区间的“最优势线段”,即在每个区间的中点处最高的线段。询问时我们可以对所有包含横坐标为 xxx 的位置的区间上的最优势线段计算答案,最后取个 maxmaxmax 。
其实这就相当于维护一个记录当前区间最高线段的,不下传标记的线段树。(显然如果我们访问到的区间内只包含询问的横坐标,那么这个区间的最优势线段就是答案线段,所以这样统计包含答案是能保证正确性的)



如上图,对于区间 [0,8][0,8][0,8] ,绿色线段是“最优势线段”

对于修改,我们先把线段的值域分割到线段树的区间上,每次访问一个完整的包含在线段值域中的区间时:

  1. 若当前区间还没有记录最优势线段,则记录最优势线段并返回。
  2. 若当前区间的最优势线段被插入的线段完全覆盖,则把最优势线段修改为被插入线段并返回。
  3. 若当前区间的最优势线段把被插入线断完全覆盖,则直接返回。
  4. 若当前区间最优势线段与被插入线段有交,则先判断哪条线段在当前区间更优,并把更劣的线段下传到交点所在子区间。(交点两边的部分被这两条线段分别控制,而我们已经让在中点更优的那条线段作为区间最优势线段,因此更劣的那条线段只有可能在交点所在子区间超过当前区间的最优势线段)

代码块:

struct Line {double k, b;//y = kx + b;int l, r, flag, idx;//线段树的l 和 r 以及是否有线段覆盖 以及插入线段的编号Line(){}//无参构造函数//有参构造函数Line(double k, double b, int l, int r, int flag, int idx) {this->k = k, this->b = b, this->l = l, this->r = r, this->flag = flag, this->idx = idx;}//算在pos位置得y值是多少double calc(int pos) {return k * pos + b;}//直线里面pos位置的y值//线段交点的x坐标int corss(const Line & rhs) const {return floor((b - rhs.b) / (rhs.k - k));}
}seg[maxn << 1];

inline void update(int cutl, int cutr, int rt,Line rhs) {//如果当前区间以及被目标区间覆盖if(rhs.l <= cutl && rhs.r >= cutr) {//如果还没有线段覆盖if(!seg[rt].flag) {seg[rt] = rhs,seg[rt].flag = 1;}//如果两端都比原线段高就直接更新else if(rhs.calc(cutl) - seg[rt].calc(cutl) > eps && rhs.calc(cutr) - seg[rt].calc(cutr) > eps) seg[rt] = rhs;//如果两线段相交else if(rhs.calc(cutl) - seg[rt].calc(cutl) > eps || rhs.calc(cutr) - seg[rt].calc(cutr) > eps) {//取中点int Mid = (cutl + cutr) >> 1;//判断两个线段中点的位置的y值大小//交换if(rhs.calc(Mid) - seg[rt].calc(Mid) > eps) swap(rhs,seg[rt]);if(rhs.corss(seg[rt]) - Mid < -eps) update(cutl, Mid, rt << 1, rhs);else update(Mid + 1, cutr, rt << 1|1,rhs);}} else {//线段树常规套路int Mid = (cutl + cutr) >> 1;if(rhs.l <= Mid) update(cutl,Mid, rt << 1,rhs);if(rhs.r > Mid) update(Mid + 1, cutr, rt << 1|1, rhs);}
}

inline void ask(int rt, int l, int r, int x) {//每一层都要跑一个询问double tmp = seg[rt].calc(x);if(tmp - h > eps) lastans = seg[rt].idx, h = tmp;else if(fabs(h - tmp) < eps) lastans = min(lastans,seg[rt].idx); if(l == r) return;if(x <= mid) ask(Lson,x);if(x > mid) ask(Rson,x);
}

#include<bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define pb push_back
#define f first
#define s second
#define y1 Y
using namespace std;
const int N = 1e7 + 10, modx = 39989, mody = 1e9;
const int maxn = 4e5 + 10;
const long double eps = 0.0;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
const int BUF=30000000;
char Buf[BUF],*buf=Buf;
template<typename T> void read(T &a)
{for(a=0;*buf<48;buf++);while(*buf>47) a=a*10+ *buf++ -48;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{read(first);read(args...);
}
int lastans = 0;
double h;
struct Line {double k, b;int l, r, flag, idx;Line(){}Line(double k, double b, int l, int r, int flag, int idx) {this->k = k, this->b = b, this->l = l, this->r = r, this->flag = flag, this->idx = idx;}double calc(int pos) {return k * pos + b;}//直线里面pos位置的y值int corss(const Line & rhs) const {return floor((b - rhs.b) / (rhs.k - k));}//线段交点的x坐标
}seg[maxn << 1];inline void build(int rt, int l, int r) {seg[rt] = (Line){0.0,0.0,l,r,0,0};if(l == r) return;build(Lson);build(Rson);
}inline void update(int cutl, int cutr, int rt,Line rhs) {if(rhs.l <= cutl && rhs.r >= cutr) {if(!seg[rt].flag) {seg[rt] = rhs,seg[rt].flag = 1;}else if(rhs.calc(cutl) - seg[rt].calc(cutl) > eps && rhs.calc(cutr) - seg[rt].calc(cutr) > eps) seg[rt] = rhs;else if(rhs.calc(cutl) - seg[rt].calc(cutl) > eps || rhs.calc(cutr) - seg[rt].calc(cutr) > eps) {int Mid = (cutl + cutr) >> 1;if(rhs.calc(Mid) - seg[rt].calc(Mid) > eps) swap(rhs,seg[rt]);if(rhs.corss(seg[rt]) - Mid < -eps) update(cutl, Mid, rt << 1, rhs);else update(Mid + 1, cutr, rt << 1|1,rhs);}} else {int Mid = (cutl + cutr) >> 1;if(rhs.l <= Mid) update(cutl,Mid, rt << 1,rhs);if(rhs.r > Mid) update(Mid + 1, cutr, rt << 1|1, rhs);}
}inline void ask(int rt, int l, int r, int x) {double tmp = seg[rt].calc(x);if(tmp - h > eps) lastans = seg[rt].idx, h = tmp;else if(fabs(h - tmp) < eps) lastans = min(lastans,seg[rt].idx); if(l == r) return;if(x <= mid) ask(Lson,x);if(x > mid) ask(Rson,x);
}
int main() {IOS;int T;cin >> T;build(1,1,100000);int Case = 1;while(T --){int op;cin >> op;if(op == 1) {int x0, y0, x1, y1;cin >> x0 >> y0 >> x1 >> y1;x0 = (x0 + lastans - 1) % modx + 1;x1 = (x1 + lastans - 1) % modx + 1;y0 = (y0 + lastans - 1) % mody + 1;y1 = (y1 + lastans - 1) % mody + 1;if(x0 == x1) {Line tmp = (Line){0.0,(double)max(y0,y1),min(x0,x1),max(x0,x1),0,Case};update(1,100000,0,tmp);} else {Line tmp = (Line){(double)(y1 - y0)/(double)(x1 - x0), (double)y0 - (double)(y1 - y0)/(double)(x1 - x0) * (double)x0,min(x0,x1),max(x0,x1),0,Case};update(1,100000,1,tmp);}Case++;} else {int k;cin >> k; h = -INF;k = (k + lastans - 1) % modx + 1;ask(1,1,100000,k);if(h == -INF) lastans = 0;cout << lastans << "\n";}}return 0;
}

李超线段树(Li-Chao Segment Tree)相关推荐

  1. 李超线段树 [Heoi2013]Segment

    问题 D: [Heoi2013]Segment 时间限制: 4 Sec 内存限制: 256 MB 题目描述 要求在平面直角坐标系下维护两个操作: 1.在平面上加入一条线段.记第i条被插入的线段的标号为 ...

  2. 【BZOJ3165】Segment(李超线段树)

    题目来源:BZOJ3165 考虑以横坐标为下标维护线段树. 在每个结点维护一个标记,表示覆盖整个结点的最高线段,注意这个标记对整个区间都有作用,无需下传. 因为只有单点询问,所以可以不用维护区间的最高 ...

  3. 【BZOJ 3165】 [Heoi2013]Segment 李超线段树

    所谓李超线段树就是解决此题一类的问题(线段覆盖查询点最大(小)),把原本计算几何的题目变成了简单的线段树,巧妙地结合了线段树的标记永久化与标记下传,在不考虑精度误差的影响下,打法应该是这样的. #in ...

  4. P4097 [HEOI2013]Segment 李超线段树

    传送门 文章目录 题意: 思路: 题意: 实现以下两个操作: (1)(1)(1)在平面上加入一条线段.记第iii条被插入的线段的标号为iii (2)(2)(2)给定一个数kkk,询问与直线x=kx=k ...

  5. 【李超线段树】BZOJ3165 [Heoi2013]Segment

    题面在这里 李超线段树的裸题,不解释 示例程序: #include<cstdio> #include<cmath> #include<algorithm> usin ...

  6. 斜率优化之凸包优化与李超线段树

    文章目录 前言 凸包优化 第一步 第二步 最后一步 例一 转移方程 凸包优化 代码 例二 题目大意 转移方程 凸包优化 代码 李超线段树 思想 插入 查询 代码 例三 代码 例四 转移方程 怎么做 代 ...

  7. BZOJ 1568 李超线段树

    思路: 李超线段树裸题 //By SiriusRen #include <cmath> #include <cstdio> #include <cstring> # ...

  8. 【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)

    Time:2016.05.10 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 李超线段树 一开始听faebdc讲,并没有听的很懂ww 后来找到良心博文啊有木有 折越 首先可以把修改 ...

  9. BZOJ 3165 李超线段树

    思路: 李超线段树 我是把线段转成斜率的形式搞得 不知道有没有更简单的方法 //By SiriusRen #include <cmath> #include <cstdio> ...

最新文章

  1. c#图片base64去转义字符_C# 将图片转成Base64字符串,再将字符串转成图片,然后将图片存储到服务器文件夹中,求代码。感激不尽...
  2. 方程AX=b的解的讨论(特解、通解、零空间向量等概念)及其MATLAB实现
  3. 深度学习和目标检测系列教程 14-300:训练第一个 YOLOv3 检测器
  4. gdb命令中attach使用
  5. HTML的script标签
  6. java 文件与base64_java之文件与base64字符之间的相互转换
  7. Rabbit MQ 配置
  8. ATM系统之问题描述与词汇表
  9. 20200203_knn分类算法
  10. 2020MathorCup第一届大数据赛B题Paddle方案
  11. 基于JAVA-公益劳动招募管理系统-计算机毕业设计源码+系统+mysql数据库+lw文档+部署
  12. sim868 c++二次开发基本完成
  13. 基于python的百度离线地图下载器
  14. #如何理解使用for循环遍历lst与lst[:],如果使用remove更改列表结果会不同
  15. 做html5抽奖程序xu,用jQuery实现抽奖程序
  16. JTextField:单行文本框组件
  17. C++练习题:计算standard_deviation
  18. 数据库系统概论--读书笔记--8 关系运算: 选择 投影 连接 除运算
  19. 通过“microbenchmark”解谜GPU的微架构
  20. 7 series FPGAs Transceiver Wizard IP核使用和测试

热门文章

  1. ACMNO.31 C语言-宏求余 输入两个整数,求他们相除的余数。用带参的宏来实现,编程序。
  2. 使用OpenVINO加速Pytorch表情识别模型
  3. 神经网络中,设计loss function有哪些技巧?
  4. BCH专属“谷歌地图”凸显BCH魅力
  5. Swift类与OC类方法相互调用的
  6. 糟糕的css用法 1
  7. RadGrid使用技巧:从RadGrid获取绑定的值
  8. Session和几种状态保持方案理解
  9. Java Swing 树状组件JTree的使用方法【图】
  10. Heartbeat双机热备配置