cp-library

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub Hoshinonono/cp-library

:warning: LiChaoTree (最大値取得)
(DataStructure/LiChaoTree_max.hpp)

概要

LiChaoTree は $ax + b$ の直線または線分を使いし、決まった1点での最小値、最大値を取得できるデータ構造。

関数名など 機能 計算量
LiChaoTree(long long L, long long R) LiChaoTree の定義域を $[Lx, Rx)$ とする。 $\text{O}(1)$
void add_line(long long a, long long b) $ax + b$ の直線を追加する。 $\text{O}(\log N)$
void add_segment_line(long long a,
long long b, long long l, long long r)
$[Lx, Rx)$ の範囲に$ax + b$ の直線を追加する。 $\text{O}(\log^{2} N)$
long long get(x) $x$ での最大値を取得する。 $\text{O}(\log N)$

Code

class LiChaoTree{
    struct Line{
        long long a, b;
        long long get(long long x){return a * x + b; }
        Line(long long a, long long b) : a(a), b(b) {}
    };
    struct Node {
        Node *left, *right;
        Line line;
        Node(Line line) : left(nullptr), right(nullptr), line(line) {}
    };
    const long long inf = (1ll << 60);
    const Line inf_line = Line{0, -inf};

    Node *root;
    long long lx, rx;
    Node* _add_line(Node *nd, Line line, long long l, long long r){
        if(l == r) return nullptr;
        if(nd == nullptr) return new Node(line);
        long long m = (l + r) >> 1;

        bool left = (line.get(l) >= nd->line.get(l));
        bool mid = (line.get(m) >= nd->line.get(m));
        bool right = (line.get(r) >= nd->line.get(r));
        if(left && right)nd->line = line;
        if(left == right)return nd;
        if(mid) std::swap(nd->line, line);
        if(left != mid){
            nd->left = _add_line(nd->left, line, l, m);
        }else{
            nd->right = _add_line(nd->right, line, m, r);
        }
        return nd;
    }
    Node* _add_segment_line(long long a, long long b, Node *nd, Line line, long long l, long long r) {
        if(r <= a || b <= l) return nd;
        if(a <= l && r <= b) return _add_line(nd, line, l, r);
        if(nd == nullptr) nd = new Node(inf_line);
        long long m = (l + r) >> 1;
        nd->left = _add_segment_line(a, b, nd->left, line, l, m);
        nd->right = _add_segment_line(a, b, nd->right, line, m, r);
        return nd;
    }
    long long query(long long x, long long l, long long r){
        Node *nd = root;
        long long res = -inf;
        while(r > l && nd != nullptr) {
            long long m = (l + r) >> 1;
            res = std::max(res, nd->line.get(x));
            if(x < m) {
                r = m;
                nd = nd->left;
            } else {
                l = m;
                nd = nd->right;
            }
        }
        return res;
    }
    public:
    LiChaoTree(long long lx, long long rx) : lx(lx), rx(rx), root(nullptr) {}
    void add_line(long long a, long long b) {
        Line line(a, b);
        root = _add_line(root, line, lx, rx);
    }
    void add_segment_line(long long a, long long b, long long l, long long r) {
        Line line = Line{a, b};
        root = _add_segment_line(l, r, root, line, lx, rx);
    }
    long long get(long long x) {
        return query(x, lx, rx);
    }
};
#line 1 "DataStructure/LiChaoTree_max.hpp"
class LiChaoTree{
    struct Line{
        long long a, b;
        long long get(long long x){return a * x + b; }
        Line(long long a, long long b) : a(a), b(b) {}
    };
    struct Node {
        Node *left, *right;
        Line line;
        Node(Line line) : left(nullptr), right(nullptr), line(line) {}
    };
    const long long inf = (1ll << 60);
    const Line inf_line = Line{0, -inf};

    Node *root;
    long long lx, rx;
    Node* _add_line(Node *nd, Line line, long long l, long long r){
        if(l == r) return nullptr;
        if(nd == nullptr) return new Node(line);
        long long m = (l + r) >> 1;

        bool left = (line.get(l) >= nd->line.get(l));
        bool mid = (line.get(m) >= nd->line.get(m));
        bool right = (line.get(r) >= nd->line.get(r));
        if(left && right)nd->line = line;
        if(left == right)return nd;
        if(mid) std::swap(nd->line, line);
        if(left != mid){
            nd->left = _add_line(nd->left, line, l, m);
        }else{
            nd->right = _add_line(nd->right, line, m, r);
        }
        return nd;
    }
    Node* _add_segment_line(long long a, long long b, Node *nd, Line line, long long l, long long r) {
        if(r <= a || b <= l) return nd;
        if(a <= l && r <= b) return _add_line(nd, line, l, r);
        if(nd == nullptr) nd = new Node(inf_line);
        long long m = (l + r) >> 1;
        nd->left = _add_segment_line(a, b, nd->left, line, l, m);
        nd->right = _add_segment_line(a, b, nd->right, line, m, r);
        return nd;
    }
    long long query(long long x, long long l, long long r){
        Node *nd = root;
        long long res = -inf;
        while(r > l && nd != nullptr) {
            long long m = (l + r) >> 1;
            res = std::max(res, nd->line.get(x));
            if(x < m) {
                r = m;
                nd = nd->left;
            } else {
                l = m;
                nd = nd->right;
            }
        }
        return res;
    }
    public:
    LiChaoTree(long long lx, long long rx) : lx(lx), rx(rx), root(nullptr) {}
    void add_line(long long a, long long b) {
        Line line(a, b);
        root = _add_line(root, line, lx, rx);
    }
    void add_segment_line(long long a, long long b, long long l, long long r) {
        Line line = Line{a, b};
        root = _add_segment_line(l, r, root, line, lx, rx);
    }
    long long get(long long x) {
        return query(x, lx, rx);
    }
};
Back to top page