李超线段树
李超线段树是一种用于在平面直角坐标系中,高效维护多个线段,并支持查询在某个横坐标 \(x\) 处,所有线段中纵坐标 \(y\) 的最大值(或最小值)的数据结构。
对于每个区间,维护完全在这个区间内的所有线段中, \(mid\) 处值最大(或最小)的线段。
插入线段时,像普通线段树一样将线段拆分成 \(\log n\) 个区间。对于每个区间,比较新线段与当前区间所保留线段在 \((mid)\) 处的取值。如果新线段在 \((mid)\) 处更优,则交换二者,并将被换下的线段继续向子区间递归插入。具体来说,若被换下的线段在左子区间(或右子区间)的某一端取值更优,则将其插入对应的子区间,以保证区间内始终保留在 \((mid)\) 处最优的线段。
这样 \(\log n\) 个拼成原区间的区间最多向下递归 \(\log n\) 层,插入时间复杂度 \(\mathcal{O}(\log^2n)\)
查询直接把路径上保留的区间在该点的值算出来,取 \(max\)(或 \(min\)),时间复杂度 \(\mathcal{O}(\log n)\)
放个模板题P4097 【模板】李超线段树 / [HEOI2013] Segment - 洛谷代码
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
inline void write(double x){printf("%lf",x);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const double eps=1e-5,inf=1e18;
struct Line{//y=kx+b;
double k,b;
int id;
double js(double x){return x*k+b;}
double js(int x){return x*k+b;}
};
bool equal(double a,double b){return abs(a-b)<eps;}
bool cmp(pair<double,int>a,pair<double,int>b){
if(equal(b.first,a.first)) return b.second>a.second;
return b.first>a.first;
}
template<int maxn>class Li_Chao_Segment_Tree{
private:
struct Node_for_Li_Chao_Segment_Tree{Line x;}t[maxn*8+10];
void insert(int u,int l,int r,int ll,int rr,Line x){
if(l>rr||r<ll) return ;
int mid=l+r>>1;
if(ll<=l&&r<=rr){
if(t[u].x.id==0){t[u].x=x;return ;}
double z1=x.js(mid),z2=t[u].x.js(mid);
if(z1>z2||equal(z1,z2)&&x.id<t[u].x.id) swap(x,t[u].x);
if(l==r) return ;
if(x.js(l)>t[u].x.js(l)) insert(u<<1,l,mid,ll,rr,x);
else insert(u<<1|1,mid+1,r,ll,rr,x);
return ;
}
if(l==r) return ;
insert(u<<1,l,mid,ll,rr,x);insert(u<<1|1,mid+1,r,ll,rr,x);
}
pair<double,int>query(int u,int l,int r,int d){
if(l>d||r<d) return {-inf,0};
pair<double,int>nans={-inf,0};
nans={t[u].x.js(d),-t[u].x.id};
// write(nans.first,nans.second,"!!");
if(l==r) return nans;
int mid=l+r>>1;
return max({query(u<<1,l,mid,d),query(u<<1|1,mid+1,r,d),nans},cmp);
}
public:
void insert(int l,int r,Line x){insert(1,1,maxn,l,r,x);}
int query(int d){return -query(1,1,maxn,d).second;}
void out(int u=1,int l=1,int r=maxn){
write(u,l,r,t[u].x.id,"!");
if(l==r) return ;
int mid=l+r>>1;
out(u<<1,l,mid),out(u<<1|1,mid+1,r);
}
};
Li_Chao_Segment_Tree<40000>t;
signed main(){
int n,ltans=0,cnt=0;read(n);
for(int i=1;i<=n;i++){
int op,x,y,xx,yy;
read(op,x);
x=(x+ltans-1+39989)%39989+1;
if(op==0) write(ltans=t.query(x)),write("\n");
else{
read(y,xx,yy);
y=(y+ltans-1+1000000000)%1000000000+1;
xx=(xx+ltans-1+39989)%39989+1;
yy=(yy+ltans-1+1000000000)%1000000000+1;
Line nw;
if(x==xx) nw.k=0,nw.b=max(1.0*y,1.0*yy);
else nw.k=1.0*(y-yy)/(x-xx),nw.b=y-x*nw.k;
nw.id=++cnt;
t.insert(min(x,xx),max(xx,x),nw);
}
// if(i==2) t.out();
}
return 0;
}
/*
3
1 8 7 3 9
1 10 9 4 3
0 8
*/

浙公网安备 33010602011771号