【瞎口胡】李超线段树
现在有如下问题:
要求在平面直角坐标系下在线维护两个操作:
- 在平面上加入一个定义域为 的一次函数。记第 个被插入的一次函数标号为 。
- 给定一个数 ,询问与直线 相交的一次函数中,交点纵坐标最大的一次函数的编号。
如果插入的一次函数横坐标为整数,那么李超树可以用线段树的分治结构在 的时间复杂度和 的空间复杂度内解决上面的问题。
概述#
李超树使用了线段树的结构,按横坐标进行分治。区间 对应节点维护的是 到 这一段区间的优势函数。要求:
- 该函数覆盖区间 。即:和 和 都有交。
- 该函数在区间中点 处的取值最大。
那么插入一个函数,会有如下几种情况发生:
- 如果当前函数定义域没有覆盖 ,那么往下递归;
- 否则,如果当前函数更优,更新当前区间的优势函数。此时被淘汰掉的函数(称为劣势函数)仍然有可能成为子区间的优势函数。
- 如果劣势函数在 处取值比优势函数大,说明这两个函数在 处有交,而在 中,劣势函数取值严格不比优势函数大,所以不可能成为右半区间的优势函数,而左半区间有机会。此时递归左半区间。
- 同理,如果劣势函数在 处取比优势函数大,递归右半区间。
查询的时候,需要比较经过的所有节点的优势函数,因为上述更新过程类似于标记永久化。
例题 [HEOI2013]Segment#
题意
同上,只不过不保证插入的是一个一次函数(可能会平行于坐标轴)。
操作次数 满足 ,横纵坐标范围分别为
题解
注意到平行于 轴不影响,平行于 轴的线段可以勉强写成 这样的形式。
直接做就可以了。
# include <bits/stdc++.h>
const int N=40010,INF=0x3f3f3f3f,MAXN=N-10,BMAX=1e9;
const double EPS=1e-8;
struct Seg{
double k,b;
inline double fx(double x){
return k*x+b;
}
}a[100010];
int n,tree[N<<2],lst,cnt; // tree[x] 存节点 x 对应的优势函数编号
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
inline int Sign(double x){
return (x>EPS)?1:((fabs(x)<EPS)?0:-1);
}
inline int lc(int x){
return x<<1;
}
inline int rc(int x){
return x<<1|1;
}
void modify(int k,int l,int r,int L,int R,int q){
if(L<=l&&r<=R){
int mid=(l+r)>>1;
int &p=tree[k];
if(Sign(a[q].fx(mid)-a[p].fx(mid))==1) std::swap(p,q);
if(Sign(a[q].fx(l)-a[p].fx(l))==1) modify(lc(k),l,mid,L,R,q);
if(Sign(a[q].fx(r)-a[p].fx(r))==1) modify(rc(k),mid+1,r,L,R,q);
return;
}
int mid=(l+r)>>1;
if(L<=mid) modify(lc(k),l,mid,L,R,q);
if(mid<R) modify(rc(k),mid+1,r,L,R,q);
return;
}
int query(int k,int l,int r,int x){
if(l==r) return tree[k];
int mid=(l+r)>>1;
int res=((x<=mid)?query(lc(k),l,mid,x):query(rc(k),mid+1,r,x)),sig=Sign(a[res].fx(x)-a[tree[k]].fx(x));
if(!sig) return std::min(res,tree[k]);
return (sig==1)?res:tree[k];
}
inline void trans(int &x,int MOD){
x=(x+lst-1)%MOD+1;
return;
}
int main(void){
n=read();
int op,k,xa,xb,ya,yb;
while(n--){
op=read();
if(!op){
k=read(),trans(k,39989);
printf("%d\n",lst=query(1,1,MAXN,k));
}else{
xa=read(),ya=read(),xb=read(),yb=read();
trans(xa,39989),trans(xb,39989),trans(ya,BMAX),trans(yb,BMAX); // 强制在线
if(xa>xb) std::swap(xa,xb),std::swap(ya,yb);
if(xa==xb) a[++cnt].k=0,a[cnt].b=std::max(ya,yb); // 特判
else a[++cnt].k=(double)(ya-yb)/(double)(xa-xb),a[cnt].b=ya-xa*a[cnt].k;
modify(1,1,MAXN,xa,xb,cnt);
}
}
return 0;
}
作者:Meatherm
出处:https://www.cnblogs.com/Meatherm/p/16542042.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
Buy me a cup of coffee ☕.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现