This documentation is automatically generated by online-judge-tools/verification-helper
#include "data_structure/li_chao_tree.hpp"
直線追加、線分追加、 $x$ における最小値を処理するデータ構造。 以下、 $N$ は処理する $x$ 座標の個数。
直線 $y = ax + b$ を追加。 $O(\log N)$
$x$ 座標の区間 $[l, r)$ に、線分 $y = ax + b$ を追加する。 $O((\log N)^2)$
$x$ における最小値を返す。 $O(\log N)$
#pragma once
#include "../template/template.hpp"
namespace lib {
template <class T> struct li_chao_tree {
private:
T f(std::pair<T, T> y, T x) const {
return y.first * x + y.second;
}
void add(std::pair<T, T> y, int l, int r, int index) {
while (l < r) {
bool left = f(y, xs[l]) < f(data[index], xs[l]);
bool mid = f(y, xs[(l + r) / 2]) < f(data[index], xs[(l + r) / 2]);
bool right = f(y, xs[r - 1]) < f(data[index], xs[r - 1]);
if (left && right) {
data[index] = y;
return;
}
if (!(left || right)) {
return;
}
if (mid) {
std::swap(y, data[index]);
left = !left;
right = !right;
}
if (left) {
r = (l + r) / 2;
index *= 2;
} else {
l = (l + r) / 2;
index = 2 * index + 1;
}
}
}
int get_index(T x) const {
auto itr = std::lower_bound(xs.begin(), xs.end(), x);
return itr - xs.begin();
}
public:
li_chao_tree(std::vector<T> &_x) : xs(_x), sz(1) {
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
while (sz < int(xs.size())) sz <<= 1;
while (int(xs.size()) < sz) xs.emplace_back(xs.back() + 1);
data.assign(2 * sz, {0, std::numeric_limits<T>::max()});
}
void add_line(T a, T b) {
add({a, b}, 0, sz, 1);
}
void add_segment(T a, T b, T lx, T rx) {
int l = get_index(lx);
int r = get_index(rx);
assert(0 <= l && l <= r && r <= sz);
int il = l + sz;
int ir = r + sz;
int rank = 0;
while (il < ir) {
if (il & 1) {
add({a, b}, l, l + (1 << rank), il++);
l += (1 << rank);
}
if (ir & 1) {
add({a, b}, r - (1 << rank), r, --ir);
r -= (1 << rank);
}
rank++;
il >>= 1;
ir >>= 1;
}
}
T min(T x) {
int k = get_index(x) + sz;
T val = std::numeric_limits<T>::max();
while (k > 0) {
val = std::min(val, f(data[k], x));
k >>= 1;
}
return val;
}
private:
std::vector<std::pair<T, T>> data;
std::vector<T> xs;
int sz;
};
}
#line 2 "data_structure/li_chao_tree.hpp"
#line 2 "template/template.hpp"
#include <bits/stdc++.h>
#define rep(i, s, n) for (int i = (int)(s); i < (int)(n); i++)
#define rrep(i, s, n) for (int i = (int)(n)-1; i >= (int)(s); i--)
#define all(v) v.begin(), v.end()
using ll = long long;
using ld = long double;
using ull = unsigned long long;
template <typename T> bool chmin(T &a, const T &b) {
if (a <= b) return false;
a = b;
return true;
}
template <typename T> bool chmax(T &a, const T &b) {
if (a >= b) return false;
a = b;
return true;
}
namespace lib {
using namespace std;
} // namespace lib
// using namespace lib;
#line 4 "data_structure/li_chao_tree.hpp"
namespace lib {
template <class T> struct li_chao_tree {
private:
T f(std::pair<T, T> y, T x) const {
return y.first * x + y.second;
}
void add(std::pair<T, T> y, int l, int r, int index) {
while (l < r) {
bool left = f(y, xs[l]) < f(data[index], xs[l]);
bool mid = f(y, xs[(l + r) / 2]) < f(data[index], xs[(l + r) / 2]);
bool right = f(y, xs[r - 1]) < f(data[index], xs[r - 1]);
if (left && right) {
data[index] = y;
return;
}
if (!(left || right)) {
return;
}
if (mid) {
std::swap(y, data[index]);
left = !left;
right = !right;
}
if (left) {
r = (l + r) / 2;
index *= 2;
} else {
l = (l + r) / 2;
index = 2 * index + 1;
}
}
}
int get_index(T x) const {
auto itr = std::lower_bound(xs.begin(), xs.end(), x);
return itr - xs.begin();
}
public:
li_chao_tree(std::vector<T> &_x) : xs(_x), sz(1) {
std::sort(xs.begin(), xs.end());
xs.erase(std::unique(xs.begin(), xs.end()), xs.end());
while (sz < int(xs.size())) sz <<= 1;
while (int(xs.size()) < sz) xs.emplace_back(xs.back() + 1);
data.assign(2 * sz, {0, std::numeric_limits<T>::max()});
}
void add_line(T a, T b) {
add({a, b}, 0, sz, 1);
}
void add_segment(T a, T b, T lx, T rx) {
int l = get_index(lx);
int r = get_index(rx);
assert(0 <= l && l <= r && r <= sz);
int il = l + sz;
int ir = r + sz;
int rank = 0;
while (il < ir) {
if (il & 1) {
add({a, b}, l, l + (1 << rank), il++);
l += (1 << rank);
}
if (ir & 1) {
add({a, b}, r - (1 << rank), r, --ir);
r -= (1 << rank);
}
rank++;
il >>= 1;
ir >>= 1;
}
}
T min(T x) {
int k = get_index(x) + sz;
T val = std::numeric_limits<T>::max();
while (k > 0) {
val = std::min(val, f(data[k], x));
k >>= 1;
}
return val;
}
private:
std::vector<std::pair<T, T>> data;
std::vector<T> xs;
int sz;
};
}