李超线段树
时间:2021-09-06
本文章向大家介绍李超线段树,主要包括李超线段树使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
李超线段树
用途:给定 $\mathrm{n}$ 个 $\mathrm{y}=\mathrm{kx}+\mathrm{b}$ 形式的线段,问 $\mathrm{x}=\mathrm{x[0]}$ 与哪条线段交点的纵坐标值最大.
对于李超树的每一个区间,维护这条区间的 “优势线段”,即区间 $\mathrm{mid}$ 位置上纵坐标最大的线段.
当在区间中插入一条线段时,按照下列步骤:
1. 若新插入线段中点位置大于当前线段,则该区间的优势线段更新为新线段,并将当前线段向下递归更新.
2. 若将递归更新的线段左/右端点的值小于优势线段,显然会完全被覆盖掉,就没有必要继续递归了.
3. 若满足递归条件,则递归继续更新.
插入线段时间复杂度为 $O(n \log ^2 n)$,查询复杂度为 $O(n \log n)$.
Segment
来源:洛谷P4097 [HEOI2013]Segment
模板题,注意线段的 $\mathrm{x[0]}=\mathrm{x[1]}$ 时将斜率取为 $0$ 即可.
#include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <set> #include <algorithm> #define M 50003 #define N 100009 #define ll long long #define pb push_back #define ls (now<<1) #define rs (now<<1|1) #define setIO(s) freopen(s".in","r",stdin) using namespace std; const int mod=39989; const double eps=1e-8; int tree[N<<2]; struct seg { double k,b; seg(double i=0.0,double j=0.0) { k=i,b=j;} }s[N]; double calc(seg o, int x) { return o.k*x+o.b; } void modify(int l,int r,int now,int L,int R,int x) { int mid=(l+r)>>1; if(l>=L&&r<=R) { if(calc(s[x],mid)-calc(s[tree[now]],mid)>eps) swap(x, tree[now]); if(calc(s[x],l)-calc(s[tree[now]],l)>eps) modify(l,mid,ls,L,R,x); if(calc(s[x],r)-calc(s[tree[now]],r)>eps) modify(mid+1,r,rs,L,R,x); return ; } if(L<=mid) modify(l,mid,ls,L,R,x); if(R>mid) modify(mid+1,r,rs,L,R,x); } void upd(int &x,int o,int p) { double yx=s[x].k*p+s[x].b; double yo=s[o].k*p+s[o].b; if(yo-yx>=eps||(abs(yo-yx)<=eps&&o<x)) x=o; } int query(int l,int r,int now,int p) { if(l==r) { return tree[now]; } int mid=(l+r)>>1,id=tree[now]; if(p<=mid) upd(id, query(l,mid,ls,p), p); else upd(id, query(mid+1,r,rs,p), p); return id; } int main() { // setIO("input"); // freopen("input.out","w",stdout); int Q,lastans=0,n=0; scanf("%d",&Q); while(Q--) { int op; scanf("%d",&op); if(op==0) { int k,x; scanf("%d",&k); k=(k+lastans-1)%mod+1; printf("%d\n",lastans=query(1,M,1,k)); } else { int x[2],y[2]; scanf("%d%d%d%d",&x[0],&y[0],&x[1],&y[1]); x[0]=(x[0]+lastans-1)%mod+1; y[0]=(y[0]+lastans-1)%1000000000+1; x[1]=(x[1]+lastans-1)%mod+1; y[1]=(y[1]+lastans-1)%1000000000+1; if(x[0]==x[1]) { s[++n].k=0,s[n].b=max(y[0], y[1]); } else { s[++n].k=(double)1.0*(y[1]-y[0])/(x[1]-x[0]); s[n].b=y[0]-1.0*s[n].k*x[0]; } if(x[0]>x[1]) swap(x[0],x[1]); modify(1,M,1,x[0],x[1],n); } } return 0; }
原文地址:https://www.cnblogs.com/brady12/p/15234637.html
- 【课堂笔记】先行者 3.0版本的vueJs课程的第二次课
- 用Python做证券指数的三种策略分析
- 明确告诉你,眼界不够,JS再好也成不了好前端
- 手把手教你整合最优雅的SSM框架
- WCF后续之旅(9):通过WCF的双向通信实现Session管理[上篇]
- 周末小贴士之“什么是语法糖”?有啥意义?
- Java反射机制深入详解
- 由for V.S. for each想到的
- 日调度5万亿次,腾讯云微服务架构体系TSF深度解读
- sed的粉丝
- 在Managed Code通过Google Gmail发送邮件以及如何通过Outlook配置Gmail
- 平方根的C语言实现(一) —— 浮点数的存储
- 用awk写递归
- bc计算A股上市新股依次涨停股价
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法