sotanishy's competitive programming library

sotanishy's code snippets for competitive programming

View the Project on GitHub sotanishy/cp-library-cpp

:warning: Nonlinear Convex Hull Trick
(data-structure/cht/nonlinear_convex_hull_trick.hpp)

Description

互いにたかだか 1 回しか交わらない関数の集合への追加クエリと最小値取得クエリを処理する.

追加クエリは次の意味での単調性を満たす必要がある:最も新しく追加された関数は,十分大きな $x$ において,集合内の関数の中で最小値を取る.

空間計算量: $O(n)$

Operations

Reference

Code

#pragma once
#include <algorithm>
#include <deque>
#include <utility>

template <typename T, typename F, T (*eval)(F, T)>
class NonlinearConvexHullTrick {
   public:
    NonlinearConvexHullTrick(T lb, T ub) : lb(lb), ub(ub) {}

    void add(const F& f) {
        T x = lb;
        while (funcs.size() >= 2 &&
               funcs.back().second >=
                   (x = intersection(funcs.back().first, f))) {
            funcs.pop_back();
        }
        if (funcs.size() == 1) x = intersection(funcs.back().first, f);
        funcs.push_back({f, x});
    }

    T get(T x) {
        while (funcs.size() >= 2 &&
               eval(funcs.front().first, x) > eval(funcs[1].first, x)) {
            funcs.pop_front();
        }
        funcs.front().second = lb;
        return eval(funcs.front().first, x);
    }

   private:
    // pair (function, intersection with the previous function)
    std::deque<std::pair<F, T>> funcs;
    T lb, ub;

    // smallest x s.t. f1(x) >= f2(x)
    T intersection(const F& f1, const F& f2) {
        T l = lb - 1, r = ub + 1;
        while (r - l > 1) {
            T m = std::midpoint(l, r);
            if (eval(f1, m) < eval(f2, m)) {
                l = m;
            } else {
                r = m;
            }
        }
        return r;
    }
};
#line 2 "data-structure/cht/nonlinear_convex_hull_trick.hpp"
#include <algorithm>
#include <deque>
#include <utility>

template <typename T, typename F, T (*eval)(F, T)>
class NonlinearConvexHullTrick {
   public:
    NonlinearConvexHullTrick(T lb, T ub) : lb(lb), ub(ub) {}

    void add(const F& f) {
        T x = lb;
        while (funcs.size() >= 2 &&
               funcs.back().second >=
                   (x = intersection(funcs.back().first, f))) {
            funcs.pop_back();
        }
        if (funcs.size() == 1) x = intersection(funcs.back().first, f);
        funcs.push_back({f, x});
    }

    T get(T x) {
        while (funcs.size() >= 2 &&
               eval(funcs.front().first, x) > eval(funcs[1].first, x)) {
            funcs.pop_front();
        }
        funcs.front().second = lb;
        return eval(funcs.front().first, x);
    }

   private:
    // pair (function, intersection with the previous function)
    std::deque<std::pair<F, T>> funcs;
    T lb, ub;

    // smallest x s.t. f1(x) >= f2(x)
    T intersection(const F& f1, const F& f2) {
        T l = lb - 1, r = ub + 1;
        while (r - l > 1) {
            T m = std::midpoint(l, r);
            if (eval(f1, m) < eval(f2, m)) {
                l = m;
            } else {
                r = m;
            }
        }
        return r;
    }
};
Back to top page