:heavy_check_mark: LiChaoTree
(data_structure/li_chao_tree.hpp)

Verified with

Code

#pragma once
#include<limits>
#include<cmath>
#include<algorithm>
/**
 * @brief LiChaoTree
 */

template<typename T>
class LHT{
    using lint = long long;
    struct node;
    using np = node*;
    struct node{
        T a,b;
        np ch[2]={nullptr,nullptr};
        node(T a,T b):a(a),b(b){}
    };
    np root=nullptr;
    T sign(T x){return (x>0)-(x<0);}
    np update(T a,T b,lint p,lint q,lint l,lint r,np t){
        if(!t)t=new node(0,std::numeric_limits<T>::max());
        //区間外
        if(r<=p||q<=l)return t;
        //全て区間内
        if(p<=l&&r<=q){
            lint m=(l+r)/2;
            if(a*m+b<=(t->a)*m+(t->b)){
                std::swap(a,t->a);
                std::swap(b,t->b);
            }
            if(r-l==1||a==t->a)return t;
            if(sign((a-t->a)*l+(b-t->b))*sign((a-t->a)*m+(b-t->b))<=0)t->ch[0]=update(a,b,p,q,l,m,t->ch[0]);
            if(sign((a-t->a)*m+(b-t->b))*sign((a-t->a)*r+(b-t->b))<=0)t->ch[1]=update(a,b,p,q,m,r,t->ch[1]);
            return t;
        }
        //一部区間内
        t->ch[0]=update(a,b,p,q,l,(l+r)/2,t->ch[0]);
        t->ch[1]=update(a,b,p,q,(l+r)/2,r,t->ch[1]);
        return t;
    }
    T get(lint x,lint l,lint r,np t){
        if(!t)return std::numeric_limits<T>::max();
        if(r-l==1)return t->a*x+t->b;
        lint m=(l+r)/2;
        if(l<=x&&x<m)return std::min(t->a*x+t->b,get(x,l,m,t->ch[0]));
        else return std::min(t->a*x+t->b,get(x,m,r,t->ch[1]));
    }
    lint mn;
    lint mx;
    public:
    LHT(lint mn=-1LL<<30,lint mx=1LL<<30):mn(mn),mx(mx){}
    T get(lint x){
        return get(x,mn,mx,root);
    }
    void add_line(T a,T b){
        root=update(a,b,mn,mx,mn,mx,root);
    }
    void add_segment(lint l,lint r,T a,T b){
        root=update(a,b,l,r,mn,mx,root);
    }
};
#line 2 "data_structure/li_chao_tree.hpp"
#include<limits>
#include<cmath>
#include<algorithm>
/**
 * @brief LiChaoTree
 */

template<typename T>
class LHT{
    using lint = long long;
    struct node;
    using np = node*;
    struct node{
        T a,b;
        np ch[2]={nullptr,nullptr};
        node(T a,T b):a(a),b(b){}
    };
    np root=nullptr;
    T sign(T x){return (x>0)-(x<0);}
    np update(T a,T b,lint p,lint q,lint l,lint r,np t){
        if(!t)t=new node(0,std::numeric_limits<T>::max());
        //区間外
        if(r<=p||q<=l)return t;
        //全て区間内
        if(p<=l&&r<=q){
            lint m=(l+r)/2;
            if(a*m+b<=(t->a)*m+(t->b)){
                std::swap(a,t->a);
                std::swap(b,t->b);
            }
            if(r-l==1||a==t->a)return t;
            if(sign((a-t->a)*l+(b-t->b))*sign((a-t->a)*m+(b-t->b))<=0)t->ch[0]=update(a,b,p,q,l,m,t->ch[0]);
            if(sign((a-t->a)*m+(b-t->b))*sign((a-t->a)*r+(b-t->b))<=0)t->ch[1]=update(a,b,p,q,m,r,t->ch[1]);
            return t;
        }
        //一部区間内
        t->ch[0]=update(a,b,p,q,l,(l+r)/2,t->ch[0]);
        t->ch[1]=update(a,b,p,q,(l+r)/2,r,t->ch[1]);
        return t;
    }
    T get(lint x,lint l,lint r,np t){
        if(!t)return std::numeric_limits<T>::max();
        if(r-l==1)return t->a*x+t->b;
        lint m=(l+r)/2;
        if(l<=x&&x<m)return std::min(t->a*x+t->b,get(x,l,m,t->ch[0]));
        else return std::min(t->a*x+t->b,get(x,m,r,t->ch[1]));
    }
    lint mn;
    lint mx;
    public:
    LHT(lint mn=-1LL<<30,lint mx=1LL<<30):mn(mn),mx(mx){}
    T get(lint x){
        return get(x,mn,mx,root);
    }
    void add_line(T a,T b){
        root=update(a,b,mn,mx,mn,mx,root);
    }
    void add_segment(lint l,lint r,T a,T b){
        root=update(a,b,l,r,mn,mx,root);
    }
};
Back to top page