李超线段树简要

· · 个人记录

d0d389d6-b769-451f-84e0-06c0e32439c4

李超线段树简要

功能:

  1. 插入一条线段 (x_1,y_1)\to (x_2,y_2),要求 x_1,x_2 是整数。

  2. 查询对于直线 x=k,所交直线所得解 y_{\max/\min}

先给出一份板子,这里推荐打动态开点。

思想:对于每个子区间 [l,r],维护一条线段满足覆盖了 [l,r],并且最优。(这个最优定义为不存在一条线段覆盖 [l,r] 的线段全面优于这条线段)。

插入:先利用线段树找到完全覆盖区间,然后我们考虑插入:

当插入线段完全优于当前线段,替换并且 return 。由于一次函数单调性,显然判断两个端点值即可。

完全劣于也直接退出。

否则两边递归——画图分析容易得到在两个子区间至少有一个会完全优于/劣于,不会继续递归。

注意特判 k=\infty 的情况

查询:一查到底,所有路过线段都有可能是答案。

李超线段树动态开点空间复杂度 O(n)

#include<bits/stdc++.h>
using namespace std;
#define N 3005050
#define db double
struct node{
    db k,b;
    void init(db _k,db x,db y){
        k=_k,b=y-x*_k;
    }
    db get(db pos){
        return k*pos+b;
    }
    bool cmp(node &a,db pos){
        return get(pos)<a.get(pos);
    }
};
#define pr pair<int,int>
#define mk make_pair
vector<pr >e[N];//every robit's time and ver
namespace mx{
    node s[N];
    int lc[N],rc[N],num,rt;
    void insert(int &x,int l,int r,int L,int R,node k){
        int mid=l+r>>1;
        if(!x)x=++num,s[x]=(node){-1e9,-1e9};
        if(L<=l&&r<=R){
            bool p=s[x].cmp(k,l),q=s[x].cmp(k,r);
            if(p^q){
                insert(lc[x],l,mid,L,R,k);insert(rc[x],mid+1,r,L,R,k);return ;
            } 
            if(p)s[x]=k;
            return ;
        }
        if(L<=mid)insert(lc[x],l,mid,L,R,k);
        if(mid<R)insert(rc[x],mid+1,r,L,R,k);
    }   
    node find(int x,int l,int r,int pos){
        if(!x)return {-1e9,-1e9};
        if(l==r)return s[x];
        int mid=l+r>>1;node res;
        if(pos<=mid)res=find(lc[x],l,mid,pos);
        else res=find(rc[x],mid+1,r,pos);
        if(s[x].cmp(res,pos))return res;
        return s[x];
    }
}
namespace mn{
    node s[N];
    int lc[N],rc[N],num,rt;
    void insert(int &x,int l,int r,int L,int R,node k){
        int mid=l+r>>1;
        if(!x)x=++num,s[x]=(node){1e9,1e9};
        if(L<=l&&r<=R){
            bool p=s[x].cmp(k,l),q=s[x].cmp(k,r);
            if(p^q){
                insert(lc[x],l,mid,L,R,k);insert(rc[x],mid+1,r,L,R,k);return ;
            } 
            if(!p)s[x]=k;
            return ;
        }
        if(L<=mid)insert(lc[x],l,mid,L,R,k);
        if(mid<R)insert(rc[x],mid+1,r,L,R,k);
    }   
    node find(int x,int l,int r,int pos){
        if(!x)return {1e9,1e9};
        if(l==r)return s[x];
        int mid=l+r>>1;node res;
        if(pos<=mid)res=find(lc[x],l,mid,pos);
        else res=find(rc[x],mid+1,r,pos);
        if(s[x].cmp(res,pos))return s[x];
        return res;
    }
}

插入线段 O(\log^2 n),插入直线 O(\log n)

运用: