李超线段树 (学习笔记)(26.1.19)

李超线段树 (学习笔记)

概述

用来去添加一些线段,然后做查询,在 \(x=k\) 的时候,去看一下交点最大值

因为可以在一些一次函数中去寻找到交点最大值,也就说明,在做斜率优化的时候,可以去套用李超线段树,直接找到最大值

所以该线段树维护的是在 $m = \frac{l+r}{2} $ 处取得的最大值的信息

思路

分别思考该怎么更新

  1. 对于新的线段 f 所覆盖区间为空,则直接为 f
  2. 对于新的线段 f 所覆盖区间的中点,比原先线段在这个区间的中点大的时候,直接替换
  3. 对于新的线段 f 所覆盖区间的中点,比原先线段在这个区间的中点小的时候,分为三种情况,分别看左右端点的关系,决定递归对象

实现

总体没有特别困难的地方,需要注意的是,在寻找某个点的值的时候要去求max,因为不能保证其中某个区间一定是最优值,因为没有下传标记

#include <bits/stdc++.h>
#define x0 x_0
#define y0 y_0
#define x1 x_1
#define y1 y_1
#define ls rt<<1
#define rs rt<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
using namespace std;
const int N = 100005;
const int MOD1 = 39989;
const int MOD2 = 1e9;
const double eee = 1e-10;
int n, lastans, cnt;

struct node{
	double k, b;
	int xmi,xma;
	double operator()(const int &x) const{
		if(xmi<=x&&x<=xma) return k*x+b;//表明当前x的高度
		//因为是线段所以要判断是否在范围内
		else return INT_MIN; 
	}
}f[N];

void add(int x0, int y0, int x1, int y1){
	++cnt;
	if(x0==x1)
		f[cnt] = {0,max(y1,y0),x0,x0};
	else
		f[cnt] = {
			1.0*(1.0*y1-y0)/(1.0*x1-x0),
        	//这里需要注意的是,因为k还没被赋值,所以只能再带入一遍
			1.0*(1.0*y1-(1.0*(1.0*y1-y0)/(1.0*x1-x0))*x1),
			x0,x1
		};
}

struct tree{
	int id[N<<2];
    //依次比较,防止爆精度
	pair<double,int> _max(pair<double,int> a,pair<double,int> b){
		if(a.first-b.first>eee) return a;
		else if(b.first-a.first>eee) return b;
		else return a.second<b.second?a:b;
	}
	//LR表示待插入线段有效区间,i为编号
	//lr表示当前节点维护的区间 
	void upd(int rt, int l, int r, int L, int R, int i){
		//第一种情况,当前节点完全有效,直接比较插入 
		if(L<=l&&r<=R){
			//当前区间无线段,直接返回 
			if(!id[rt]){id[rt]=i;return;}
			//取中间值比较 
			int mid = (l+r)>>1;
			//交换可以的线段,递归被淘汰的线段
			//交换后为第二种情况,看左右节点 
			if(f[i](mid)-f[id[rt]](mid)>eee) swap(i,id[rt]);
			if(f[i](l)-f[id[rt]](l)>eee||(fabs(f[i](l)-f[id[rt]](l))<=eee&&i<id[rt])) upd(lson,L,R,i);
			if(f[i](r)-f[id[rt]](r)>eee||(fabs(f[i](r)-f[id[rt]](r))<=eee&&i<id[rt])) upd(rson,L,R,i);
			return;
		}
		int mid = (l+r)>>1;
		if(L<=mid) upd(lson,L,R,i);//左子树有交集就递归左子树
		if(mid<R)  upd(rson,L,R,i); 
	}
	//这个答案也是,因为不能确保单点就是最优值,只能确保当前包含这个点的区间内的最 
	pair<double, int> query(int rt, int l, int r, int k){
		pair<double, int> ans;
		if(id[rt]) ans = make_pair(f[id[rt]](k), id[rt]);
		if(l==r) return ans;
		int mid = (l+r)>>1;
		//去一直查找与k有交集的 
		if(k<=mid) ans = _max(query(lson,k),ans);
		else ans = _max(query(rson,k),ans);
		return ans;
	}
}yuriha;
int main(){
	cin>>n;
	while(n--){
		int op;cin>>op;
		if(!op){
			int x;cin>>x;
			x = (x+lastans-1+MOD1)%MOD1+1;
			lastans = yuriha.query(1,1,MOD1,x).second;
			cout<<lastans<<'\n';
		}
		else{
			int x0,y0,x1,y1;
			cin>>x0>>y0>>x1>>y1;
			x0 = (x0+lastans-1+MOD1)%MOD1+1,
			x1 = (x1+lastans-1+MOD1)%MOD1+1,
			y0 = (y0+lastans-1+MOD2)%MOD2+1,
			y1 = (y1+lastans-1+MOD2)%MOD2+1;
			if(x0>x1) swap(x0,x1),swap(y0,y1);
			add(x0,y0,x1,y1);
			yuriha.upd(1,1,MOD1,x0,x1,cnt);
		}
	}
	return 0;
}
posted @ 2026-01-19 20:51  Yuriha  阅读(25)  评论(0)    收藏  举报