On this page
article
SlopeTrick
Sobre
Armazena uma estrutura convexa piecewise linear
Permite adicionar slopes sem peso e realizar query de minimo
Comentarios acima das funcoes para explicar o que cada uma faz
Link original: slopeTrick.cpp
Código
template<typename T> struct SlopeTrick {
T inf = numeric_limits<T>::max() / 3;
T min_f;
priority_queue<T, vector<T>, less<>> L;
priority_queue<T, vector<T>, greater<>> R;
T add_l, add_r;
T top_R() {
if (R.empty()) return inf;
else return R.top() + add_r;
}
T pop_R() {
T val = top_R();
if (R.size()) R.pop();
return val;
}
T top_L() {
if (L.empty()) return -inf;
else return L.top() + add_l;
}
T pop_L() {
T val = top_L();
if (L.size()) L.pop();
return val;
}
size_t size() {
return L.size() + R.size();
}
SlopeTrick() : min_f(0), add_l(0), add_r(0) {};
// return {min f(x), lx, rx}
// Em que [lx, rx] eh o intervalo que atinge o minimo
array<T, 3> query() {
return {min_f, top_L(), top_R()};
}
// f(x) += a
void add_all(T a) {
min_f += a;
}
// add \_
// f(x) += max(a - x, 0)
void add_a_minus_x(T a) {
min_f += max(T(0), a - top_R());
R.push(a - add_r);
L.push(pop_R() - add_l);
}
// add _/
// f(x) += max(x - a, 0)
void add_x_minus_a(T a) {
min_f += max(T(0), top_L() - a);
L.push(a - add_l);
R.push(pop_L() - add_r);
}
// add \/
// f(x) += abs(x - a)
void add_abs(T a) {
add_a_minus_x(a);
add_x_minus_a(a);
}
// \/ -> \_
// f_{new} (x) = min f(y) (y <= x)
void clear_right() {
while (R.size()) R.pop();
}
// \/ -> _/
// f_{new} (x) = min f(y) (y >= x)
void clear_left() {
while (L.size()) L.pop();
}
// \/ -> \_/
// f_{new} (x) = min f(y) (x-b <= y <= x-a)
void shift(T a, T b) {
assert(a <= b);
add_l += a;
add_r += b;
}
// \/. -> .\/
// f_{new} (x) = f(x - a)
void shift(T a) {
shift(a, a);
}
// Retorna f(x)
// O(size)
T get(T x) {
auto L2 = L;
auto R2 = R;
T ret = min_f;
while (L.size()) {
ret += max(T(0), pop_L() - x);
}
while (R.size()) {
ret += max(T(0), x - pop_R());
}
L = L2, R = R2;
return ret;
}
// O(min(size, st.size))
void merge(SlopeTrick &st) {
if (st.size() > size()) {
swap(*this, st);
}
while (st.R.size()) {
add_x_minus_a(st.pop_R());
}
while (st.L.size()) {
add_a_minus_x(st.pop_L());
}
min_f += st.min_f;
}
};