【瞎口胡】李超线段树

现在有如下问题:

要求在平面直角坐标系下在线维护两个操作:

  1. 在平面上加入一个定义域为 [l,r] 的一次函数。记第 i 个被插入的一次函数标号为 i
  2. 给定一个数 k,询问与直线 x=k 相交的一次函数中,交点纵坐标最大的一次函数的编号。

如果插入的一次函数横坐标为整数,那么李超树可以用线段树的分治结构在 O(nlogn) 的时间复杂度和 O(n) 的空间复杂度内解决上面的问题。

概述#

李超树使用了线段树的结构,按横坐标进行分治。区间 [l,r] 对应节点维护的是 x=lx=r 这一段区间的优势函数。要求:

  • 该函数覆盖区间 [l,r]。即:和 x=lx=r 都有交。
  • 该函数在区间中点 mid 处的取值最大。

那么插入一个函数,会有如下几种情况发生:

  • 如果当前函数定义域没有覆盖 [l,r],那么往下递归;
  • 否则,如果当前函数更优,更新当前区间的优势函数。此时被淘汰掉的函数(称为劣势函数)仍然有可能成为子区间的优势函数。
    • 如果劣势函数在 x=l 处取值比优势函数大,说明这两个函数在 [l,mid] 处有交,而在 [mid,r] 中,劣势函数取值严格不比优势函数大,所以不可能成为右半区间的优势函数,而左半区间有机会。此时递归左半区间。
    • 同理,如果劣势函数在 x=r 处取比优势函数大,递归右半区间。

查询的时候,需要比较经过的所有节点的优势函数,因为上述更新过程类似于标记永久化

例题 [HEOI2013]Segment#

题意

同上,只不过不保证插入的是一个一次函数(可能会平行于坐标轴)。

操作次数 n 满足 1n105,横纵坐标范围分别为 [1,39989],[1,109]

题解

注意到平行于 x 轴不影响,平行于 y 轴的线段可以勉强写成 y=0x+max{y0,y1} 这样的形式。

直接做就可以了。

# 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 国际」许可协议进行许可。

posted @   Meatherm  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示