李超线段树
李超线段树
李超线段树是一种维护空间一次函数的结构。
定义线段树中的一个节点l~r所表示的区间为一个空间“域”的话。
定义最优势直线为区间为整个区间自上而下覆盖范围最广的直线。
线段树中储存的信息,实际上是每个空间“域”内最优势的一次函数。
从本质上来讲李超树,是一种标记永久化的线段树。
它每次推标记的时候都会二分向左或者向右,不会同时向两边推标记,这就使得它可以暴力推标记推到叶子节点。
讲解
模版
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=8e6+10101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-12;
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct line{
double k,b;
int l,r,flag;
line(){k=b=0.0,flag=0;}
double calc(double pos){
return k*pos+b;
}
int cross(line x){
return floor((b-x.b)/(x.k-k));
}
}tr[maxn],tre[maxn];
int n,m;
void update(int k,int l,int r,line add){
if(add.l<=l && r<=add.r){
if(!tr[k].flag){
tr[k]=add;
}
else if(add.calc(l)-tr[k].calc(l)>eps && add.calc(r)-tr[k].calc(r)>eps){
tr[k]=add;
}
else if(add.calc(l)-tr[k].calc(l)>eps || add.calc(r)-tr[k].calc(r)>eps){
int mid=(l+r)>>1;
if(add.calc(mid)-tr[k].calc(mid)>eps)swap(tr[k],add);
if(add.cross(tr[k])-mid<-eps)update(k<<1,l,mid,add);
else update(k<<1|1,mid+1,r,add);
}
}
else {
int mid=(l+r)>>1;
if(add.l<=mid)update(k<<1,l,mid,add);
if(add.r>mid)update(k<<1|1,mid+1,r,add);
}
return ;
}
void update1(int k,int l,int r,line add){
if(add.l<=l && r<=add.r){
if(!tre[k].flag){
tre[k]=add;
}
else if(tre[k].calc(l)-add.calc(l)>eps && tre[k].calc(r)-add.calc(r)>eps){
tre[k]=add;
}
else if(tre[k].calc(l)-add.calc(l)>eps || tre[k].calc(r)-add.calc(r)>eps){
int mid=(l+r)>>1;
if(tre[k].calc(mid)-add.calc(mid)>eps)swap(tre[k],add);
if(add.cross(tre[k])-mid<-eps)update1(k<<1,l,mid,add);
else update1(k<<1|1,mid+1,r,add);
}
}
else {
int mid=(l+r)>>1;
if(add.l<=mid)update1(k<<1,l,mid,add);
if(add.r>mid)update1(k<<1|1,mid+1,r,add);
}
return ;
}
double querymax(int k,int l,int r,int x){
if(l==r)return tr[k].calc(x);
int mid=(l+r)>>1;
double ans=tr[k].calc(x);
if(x<=mid && tr[k<<1].flag)ans=max(ans,querymax(k<<1,l,mid,x));
else if(tr[k<<1|1].flag)ans=max(ans,querymax(k<<1|1,mid+1,r,x));
return ans;
}
double querymin(int k,int l,int r,int x){
if(l==r){
return tre[k].calc(x);
}
int mid=(l+r)>>1;
double ans=tre[k].calc(x);
if(x<=mid && tre[k<<1].flag)ans=min(ans,querymin(k<<1,l,mid,x));
else if(tre[k<<1|1].flag)ans=min(ans,querymin(k<<1|1,mid+1,r,x));
return ans;
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int opt=read();
if(!opt){
int k=read(),b=read();
line now;
now.k=k;now.b=b;now.l=1;now.r=n;now.flag=1;
update(1,1,n,now);
update1(1,1,n,now);
}
else {
int x=read();
printf("%lld %lld\n",(ll)querymax(1,1,n,x),(ll)querymin(1,1,n,x));
}
}
return 0;
}
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#define ll long long
#define pa pair<int,double>
using namespace std;
const int maxn=1e6+10101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-12;
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct line{
double k,b;
int l,r,flag,id;
line(){k=b=0.0,flag=id=0;}
double calc(double pos){
return k*pos+b;
}
int cross(line x){
return floor((b-x.b)/(x.k-k));
}
}tr[maxn];
int n,m;
void update(int k,int l,int r,line add){
if(add.l<=l && r<=add.r){
if(!tr[k].flag){
tr[k]=add;
}
else if(add.calc(l)-tr[k].calc(l)>eps && add.calc(r)-tr[k].calc(r)>eps){
tr[k]=add;
}
else if(add.calc(l)-tr[k].calc(l)>eps || add.calc(r)-tr[k].calc(r)>eps){
int mid=(l+r)>>1;
if(add.calc(mid)-tr[k].calc(mid)>eps)swap(tr[k],add);
if(add.cross(tr[k])-mid<-eps)update(k<<1,l,mid,add);
else update(k<<1|1,mid+1,r,add);
}
}
else {
int mid=(l+r)>>1;
if(add.l<=mid)update(k<<1,l,mid,add);
if(add.r>mid)update(k<<1|1,mid+1,r,add);
}
return ;
}
int last;
double jilu;
void querymax(int k,int l,int r,int x){
if(l==r){
if(tr[k].flag && tr[k].calc(x)-jilu>eps)jilu=tr[k].calc(x),last=tr[k].id;
return ;
}
int mid=(l+r)>>1;
if(tr[k].flag && tr[k].calc(x)-jilu>eps)jilu=tr[k].calc(x),last=tr[k].id;
if(x<=mid)querymax(k<<1,l,mid,x);
else querymax(k<<1|1,mid+1,r,x);
return ;
}
int main(){
n=read();int cnt=0;
for(int i=1;i<=n;i++){
int op=read();
if(!op){
int k=read();
k=((k+last-1)%39989+1);jilu=0;last=0;
querymax(1,1,40000,k);
printf("%d\n",last);
}
else {
int x0=read(),y0=read(),x1=read(),y1=read();
x0=((x0+last-1)%39989+1);
y0=((y0+last-1)%1000000000+1);
x1=((x1+last-1)%39989+1);
y1=((y1+last-1)%1000000000+1);
if(x0>x1)swap(x0,x1),swap(y0,y1);
line now;
now.flag=1;
if(x1==x0)now.k=0;
else now.k=(double)(y1-y0)/(double)(x1-x0);
now.b=(double)y0-(double)(now.k*(double)x0);
now.l=x0;now.r=x1;now.id=++cnt;
update(1,1,40000,now);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!