李超线段树入门
李超线段树入门
算法总概
李超线段树用于维护线段和直线与某条直线交点的最值
类似一个凸包的东西
大致思路:
插入时通过线段树记录与更新,每个区间可能的最优的直线
查询时,对于覆盖在某个点之上的所有区间求其最值
插入的细节(现在考虑最大值):
- 若当前区间没有直线,加入当前直线即可
- 若"区间直线"整体在"插入直线"下,整体替换
- 若"插入直线"整体在"区间直线"下,不做更改
- 两直线有交点则判断交点的位置,并下放插入直线到左右儿子
code
例题(求所有直线与x=x0的交点的最大值)
#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define get getchar()
#define in inline
#define db double
const int _=2e5+234;
int n;
char ch[101];
struct LCXDtree{
db b, k;
int fl;
}a[_<<2];
#define ls k<<1
#define rs k<<1|1
in void insert(int k,int l,int r,db K,db B)
{
if(l>r) return;
if(!a[k].fl){ a[k].fl=1; a[k].k=K, a[k].b=B; return;}
int l1=a[k].k*(l-1)+a[k].b, l2=K*(l-1)+B, r1=a[k].k*(r-1)+a[k].b, r2=K*(r-1)+B;
if(l1>=l2 && r1>=r2) return;
if(l1<l2 && r1<r2){ a[k].k=K, a[k].b=B; return;}
int mid=l+r>>1, mid1=a[k].k*(mid-1)+a[k].b, mid2=K*(mid-1)+B;
if(l1<l2)
{
insert(ls,l,mid,K,B);
if(mid1<mid2) insert(rs,mid+1,r,K,B);
}
else
{
insert(rs,mid+1,r,K,B);
if(mid1<mid2) insert(ls,l,mid,K,B);
}
}
in db query(int k,int l,int r,int x)
{
if(l==r) return a[k].k*(l-1)+a[k].b;
int mid=l+r>>1; db w=a[k].k*(x-1)+a[k].b;
if(x<=mid) return max(w,query(ls,l,mid,x));
else return max(w,query(rs,mid+1,r,x));
}
int main()
{
int T; cin>>T; n=50000;
while(T--)
{
cin>>ch+1;
if(ch[1]=='P')
{
db x,y; scanf("%lf%lf",&x,&y);
insert(1,1,n,y,x);
}
else
{
int x; scanf("%d", &x);
printf("%d\n", int(query(1,1,n,x))/100);
}
}
return 0;
}
嗯,就这样了...