Loading

【瞎口胡】李超线段树

现在有如下问题:

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

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

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

概述

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

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

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

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

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

例题 [HEOI2013]Segment

题意

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

操作次数 \(n\) 满足 \(1 \leq n\leq 10^5\),横纵坐标范围分别为 \([1,39989],[1,10^9]\)

题解

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

直接做就可以了。

# 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;
}

posted @ 2022-08-01 22:07  Meatherm  阅读(41)  评论(0编辑  收藏  举报