李超线段树的主要用途:插入线段,查询单点极值
用线段树维护 x 轴,每个区间节点 [l,r] 保存 x 取 mid=l+r2 的最优 y 的线段编号,对于一个新来的线段 line,设线段 line 的 x 范围为 [l,r],则该线段只会对被该区间包含的线段树节点区间有影响,即先找到被影响的线段树节点,如果当前线段树中没有保存编号,则直接将该节点作为整个线段树的初始最优编号,否则将线段 line 跟线段树中保存的线段 line′ 进行比较,如果对于节点区间中心 mid 来说 line 要更优则当前线段树节点保存 line 这条线段,假设 line 要比 line′ 更劣,如果对于节点区间左端点来说,新线段 line 要比 line′ 更优,则说明左子树表示的区间有部分区间不如 line 优,往左子树递归,右端点同理,查询单点极值暴力查询即可
时间复杂度:O(mlogn)
代码
// Problem: P4097 [HEOI2013]Segment// Contest: Luogu// URL: https://www.luogu.com.cn/problem/P4097// Memory Limit: 128 MB// Time Limit: 1000 ms// // Powered by CP Editor (https://cpeditor.org)// %%%Skyqwq#include<bits/stdc++.h>//#define int long long#define help {cin.tie(NULL); cout.tie(NULL);}#define pb push_back#define fi first#define se second#define mkp make_pairusingnamespace std;
typedeflonglong LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> boolchkMax(T &x, T y){ return (y > x) ? x = y, 1 : 0; }
template <typename T> boolchkMin(T &x, T y){ return (y < x) ? x = y, 1 : 0; }
template <typename T> voidinlineread(T &x){
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
typedef pair<double,int> PDI;
constint N=40005,M=1e5+5,mod1=39989,mod2=1e9;
constdouble eps=1e-8;
int n;
structLine{
double k,b;
}line[M];
structTr{
int l,r,id;
}tr[N<<2];
voidbuild(int p,int l,int r){
tr[p]={l,r};
if(l==r)
return ;
int mid=l+r>>1;
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
}
doubleget(int id,int x){
return line[id].k*x+line[id].b;
}
intcmp(double a,double b){
if(a-b>eps)return1;
if(b-a>eps)return-1;
return0;
}
voidupdate(int p,int l,int r,int id){
if(l<=tr[p].l&&tr[p].r<=r)
{
if(!tr[p].id)tr[p].id=id;
else {
int &tid=tr[p].id;
int mid=tr[p].l+tr[p].r>>1;
double new_y=get(id,mid),old_y=get(tid,mid);
if(cmp(new_y,old_y)==1)swap(tid,id);
if(tr[p].l==tr[p].r)return ;
int judgel=cmp(get(id,l),get(tid,l));
int judger=cmp(get(id,r),get(tid,r));
if(judgel==1||(!judgel&&id<tid))update(p<<1,l,r,id);
if(judger==1||(!judger&&id<tid))update(p<<1|1,l,r,id);
}
return ;
}
int mid=tr[p].l+tr[p].r>>1;
if(l<=mid)update(p<<1,l,r,id);
if(r>mid)update(p<<1|1,l,r,id);
}
PDI MAX(PDI a,PDI b){
if(cmp(a.fi,b.fi)==1)return a;
elseif(cmp(a.fi,b.fi)==-1)return b;
return a.se<b.se?a:b;
}
PDI ask(int p,int x){
if(x<tr[p].l||x>tr[p].r)return {0,0};
PDI res={get(tr[p].id,x),tr[p].id};
if(tr[p].l==tr[p].r)return res;
res=MAX(res,ask(p<<1,x));
res=MAX(res,ask(p<<1|1,x));
return res;
}
intmain(){
build(1,1,40000);
int lstans=0,cnt;
int t=0;
for(scanf("%d",&n);n;n--)
{
int x0,y0,x1,y1,k,op;
scanf("%d",&op);
if(op)
{
scanf("%d%d%d%d",&x0,&y0,&x1,&y1);
x0=(x0+lstans-1)%mod1+1,x1=(x1+lstans-1)%mod1+1;
y0=(y0+lstans-1)%mod2+1,y1=(y1+lstans-1)%mod2+1;
if(x0>x1)swap(x0,x1),swap(y0,y1);
if(x0==x1)line[++cnt]={0,(double)max(y0,y1)};
else line[++cnt]={(double)(y1-y0)/(x1-x0),y1-(double)(y1-y0)/(x1-x0)*x1};
update(1,x0,x1,cnt);
}
else {
scanf("%d",&k);
k=(k+lstans-1)%mod1+1;
printf("%d\n",lstans=ask(1,k).se);
}
}
return0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2021-10-20 阶乘分解