李超线段树入门

李超线段树入门

算法总概

李超线段树用于维护线段和直线与某条直线交点的最值
类似一个凸包的东西

大致思路:

插入时通过线段树记录与更新,每个区间可能的最优的直线
查询时,对于覆盖在某个点之上的所有区间求其最值

插入的细节(现在考虑最大值):

  1. 若当前区间没有直线,加入当前直线即可
  2. "区间直线"整体在"插入直线"下,整体替换
  3. "插入直线"整体在"区间直线"下,不做更改
  4. 两直线有交点则判断交点的位置,并下放插入直线到左右儿子

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;
}
posted @ 2021-09-12 22:03  yzhx  阅读(74)  评论(0编辑  收藏  举报