李超线段树 (学习笔记)(26.1.19)
李超线段树 (学习笔记)
概述
用来去添加一些线段,然后做查询,在 \(x=k\) 的时候,去看一下交点最大值
因为可以在一些一次函数中去寻找到交点最大值,也就说明,在做斜率优化的时候,可以去套用李超线段树,直接找到最大值
所以该线段树维护的是在 $m = \frac{l+r}{2} $ 处取得的最大值的信息
思路
分别思考该怎么更新
- 对于新的线段 f 所覆盖区间为空,则直接为 f
- 对于新的线段 f 所覆盖区间的中点,比原先线段在这个区间的中点大的时候,直接替换
- 对于新的线段 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;
}

浙公网安备 33010602011771号