Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 0 additions & 95 deletions segmenttree/acl_beats.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#pragma once
#include "acl_lazysegtree.hpp"

#include <algorithm>
#include <iostream>

template <class S, auto op, auto e, class F, auto mapping, auto composition, auto id>
class segtree_beats : public atcoder::lazy_segtree<S, op, e, F, mapping, composition, id> {
using Base = atcoder::lazy_segtree<S, op, e, F, mapping, composition, id>;
Expand All @@ -16,95 +13,3 @@ class segtree_beats : public atcoder::lazy_segtree<S, op, e, F, mapping, composi
}
}
};

namespace RangeChMinMaxAddSum {
template <typename Num> inline Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept {
assert(a <= a2); // a < a2 or a == a2 == INF
assert(c <= c2); // c < c2 or c == c2 == -INF
return a == c ? std::min(a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max(a, c);
}
template <typename Num> inline Num second_highest(Num a, Num a2, Num b, Num b2) noexcept {
assert(a >= a2); // a > a2 or a == a2 == -INF
assert(b >= b2); // b > b2 or b == b2 == INF
return a == b ? std::max(a2, b2) : a2 >= b ? a2 : b2 >= a ? b2 : std::min(a, b);
}

using BNum = long long;
constexpr BNum BINF = 1LL << 61;

struct S {
BNum lo, hi, lo2, hi2, sum;
unsigned sz, nlo, nhi;
bool fail;
S() : lo(BINF), hi(-BINF), lo2(BINF), hi2(-BINF), sum(0), sz(0), nlo(0), nhi(0), fail(0) {}
S(BNum x, unsigned sz_)
: lo(x), hi(x), lo2(BINF), hi2(-BINF), sum(x * sz_), sz(sz_), nlo(sz_), nhi(sz_), fail(0) {}
friend std::ostream &operator<<(std::ostream &os, const S s) {
return os << "[(" << s.lo << "x" << s.nlo << ", " << s.lo2 << ", " << s.hi2 << ", " << s.hi
<< "x" << s.nhi << "), sz=" << s.sz << ", sum=" << s.sum << "]";
}
};

S e() { return S(); }
S op(S l, S r) {
if (l.lo > l.hi) return r;
if (r.lo > r.hi) return l;
S ret;
ret.lo = std::min(l.lo, r.lo);
ret.hi = std::max(l.hi, r.hi);
ret.lo2 = second_lowest(l.lo, l.lo2, r.lo, r.lo2),
ret.hi2 = second_highest(l.hi, l.hi2, r.hi, r.hi2);
ret.sum = l.sum + r.sum;
ret.sz = l.sz + r.sz;
ret.nlo = l.nlo * (l.lo <= r.lo) + r.nlo * (r.lo <= l.lo);
ret.nhi = l.nhi * (l.hi >= r.hi) + r.nhi * (r.hi >= l.hi);
return ret;
}
struct F {
BNum lb, ub, bias;
F() : lb(-BINF), ub(BINF), bias(0) {}
F(BNum chmax_, BNum chmin_, BNum add) : lb(chmax_), ub(chmin_), bias(add) {}
static F chmin(BNum x) noexcept { return F(-BINF, x, BNum(0)); }
static F chmax(BNum x) noexcept { return F(x, BINF, BNum(0)); }
static F add(BNum x) noexcept { return F(-BINF, BINF, x); };
};

F composition(F fnew, F fold) {
F ret;
ret.lb = std::max(std::min(fold.lb + fold.bias, fnew.ub), fnew.lb) - fold.bias;
ret.ub = std::min(std::max(fold.ub + fold.bias, fnew.lb), fnew.ub) - fold.bias;
ret.bias = fold.bias + fnew.bias;
return ret;
}
F id() { return F(); }
S mapping(F f, S x) {
if (x.sz == 0) return e();

// f の作用後 x の要素が 1 種類だけになるケース
if (x.lo == x.hi or f.lb == f.ub or f.lb >= x.hi or f.ub <= x.lo) {
return S(std::min(std::max(x.lo, f.lb), f.ub) + f.bias, x.sz);
}

// 2 種類 -> 1 種類
if (x.lo2 == x.hi) {
x.lo = x.hi2 = std::max(x.lo, f.lb) + f.bias;
x.hi = x.lo2 = std::min(x.hi, f.ub) + f.bias;
x.sum = x.lo * x.nlo + x.hi * x.nhi;
return x;
}

// lo と lo2, hi と hi2 が潰れないケース
if (f.lb < x.lo2 and f.ub > x.hi2) {
BNum nxt_lo = std::max(x.lo, f.lb), nxt_hi = std::min(x.hi, f.ub);
x.sum += (nxt_lo - x.lo) * x.nlo - (x.hi - nxt_hi) * x.nhi + f.bias * x.sz;
x.lo = nxt_lo + f.bias, x.hi = nxt_hi + f.bias, x.lo2 += f.bias, x.hi2 += f.bias;
return x;
}

x.fail = 1;
return x;
}

using segtree = segtree_beats<S, op, e, F, mapping, composition, id>;

} // namespace RangeChMinMaxAddSum
18 changes: 11 additions & 7 deletions segmenttree/test/beats.test.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
#define PROBLEM "https://judge.yosupo.jp/problem/range_chmin_chmax_add_range_sum"
#include "../acl_beats.hpp"
#include "../trees/range-chmin-chmax-add-range-sum.hpp"
#include <iostream>
#include <vector>
using namespace std;

using RCCARS = RangeChminChmaxAddRangeSum<long long, (1LL << 60)>;

int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);
int N, Q;
cin >> N >> Q;
vector<RangeChMinMaxAddSum::S> A(N);
vector<RCCARS::S> A(N);
for (auto &a : A) {
long long tmp;
cin >> tmp, a = {tmp, 1};
cin >> tmp, a = RCCARS::Gen(tmp);
}
RangeChMinMaxAddSum::segtree segtree(A);

RCCARS::segtree segtree(A);

while (Q--) {
int q, l, r;
long long b;
cin >> q >> l >> r;
if (q < 3) {
cin >> b;
if (q == 0) segtree.apply(l, r, RangeChMinMaxAddSum::F::chmin(b));
if (q == 1) segtree.apply(l, r, RangeChMinMaxAddSum::F::chmax(b));
if (q == 2) segtree.apply(l, r, RangeChMinMaxAddSum::F::add(b));
if (q == 0) segtree.apply(l, r, RCCARS::Chmin(b));
if (q == 1) segtree.apply(l, r, RCCARS::Chmax(b));
if (q == 2) segtree.apply(l, r, RCCARS::Add(b));
} else {
long long ret = segtree.prod(l, r).sum;
cout << ret << '\n';
Expand Down
20 changes: 9 additions & 11 deletions segmenttree/test/beats_random_test.test.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" // DUMMY

#include "../../random/xorshift.hpp"
#include "../acl_beats.hpp"
#include "../trees/range-chmin-chmax-add-range-sum.hpp"

#include <algorithm>
#include <cstdio>
#include <numeric>
#include <vector>

using RangeChMinMaxAddSum::S, RangeChMinMaxAddSum::F;
using RCCARS = RangeChminChmaxAddRangeSum<long long, (1LL << 60)>;

int main() {
for (int trial = 0; trial < 1 << 20; ++trial) {
Expand All @@ -17,16 +17,14 @@ int main() {
const int maxA = rand_int() % 50 + 1;
const int Q = rand_int() % 10 + 1;

std::vector<S> A(N);
std::vector<RCCARS::S> A(N);
std::vector<int> simulate(N);
for (int i = 0; i < N; ++i) {
simulate.at(i) = rand_int() % (maxA + 1);
A.at(i) = S(simulate.at(i), 1);
A.at(i) = RCCARS::Gen(simulate.at(i));
}

segtree_beats<S, RangeChMinMaxAddSum::op, RangeChMinMaxAddSum::e, F, RangeChMinMaxAddSum::mapping,
RangeChMinMaxAddSum::composition, RangeChMinMaxAddSum::id>
segtree(A);
RCCARS::segtree segtree(A);

for (int q = 0; q < Q; ++q) {
int tp = rand_int() % 4;
Expand All @@ -43,17 +41,17 @@ int main() {
int b = rand_int() % (maxA + 1);
if (tp == 0) {
for (int i = l; i < r; ++i) simulate.at(i) = std::min(simulate.at(i), b);
segtree.apply(l, r, RangeChMinMaxAddSum::F::chmin(b));
segtree.apply(l, r, RCCARS::Chmin(b));
}

if (tp == 1) {
for (int i = l; i < r; ++i) simulate.at(i) = std::max(simulate.at(i), b);
segtree.apply(l, r, RangeChMinMaxAddSum::F::chmax(b));
segtree.apply(l, r, RCCARS::Chmax(b));
}

if (tp == 2) {
for (int i = l; i < r; ++i) simulate.at(i) += b;
segtree.apply(l, r, RangeChMinMaxAddSum::F::add(b));
segtree.apply(l, r, RCCARS::Add(b));
}
}

Expand All @@ -72,7 +70,7 @@ int main() {

assert(prod.sum == std::accumulate(values.begin(), values.end(), 0LL));

assert(prod.sz == r - l);
assert((int)prod.sz == r - l);
assert(!prod.fail);

if (values.front() != values.back()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
#include "../trees/acl_range-add-chmax-range-sum.hpp"
#include "../trees/range-chmax-add-range-sum.hpp"
#define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0427"
#include <iostream>
using namespace std;

using RCARS = RangeChmaxAddRangeSum<long long, (1LL << 60)>;

int main() {
cin.tie(nullptr), ios::sync_with_stdio(false);

int N, tmp;
cin >> N;
vector<RangeAddChmaxRangeSum::S> A(N);
for (auto &a : A) cin >> tmp, a = tmp;
vector<RCARS::S> A(N);
for (auto &a : A) cin >> tmp, a = RCARS::Gen(tmp);

RangeAddChmaxRangeSum::segtree segtree(A);
RCARS::segtree segtree(A);

int Q, q, l, r, d;
cin >> Q;
Expand All @@ -20,12 +22,12 @@ int main() {
cin >> q >> l >> r >> d;
l--;
if (q == 1) {
segtree.apply(l, r, RangeAddChmaxRangeSum::F::add(d));
segtree.apply(l, r, RCARS::Add(d));
} else {
auto before = segtree.prod(l, r).sum;
auto f1 = RangeAddChmaxRangeSum::F::add(-d);
auto f2 = RangeAddChmaxRangeSum::F::chmax(0);
segtree.apply(l, r, RangeAddChmaxRangeSum::composition(f2, f1));
auto f1 = RCARS::Add(-d);
auto f2 = RCARS::Chmax(0);
segtree.apply(l, r, RCARS::composition(f2, f1));
auto after = segtree.prod(l, r).sum;
cout << before - after << '\n';
}
Expand Down
64 changes: 0 additions & 64 deletions segmenttree/trees/acl_range-add-chmax-range-sum.hpp

This file was deleted.

79 changes: 79 additions & 0 deletions segmenttree/trees/range-chmax-add-range-sum.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#pragma once
#include "../acl_beats.hpp"
#include <algorithm>
#include <type_traits>

// Verified: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0427
template <typename Num, Num INF> struct RangeChmaxAddRangeSum {
static_assert(std::is_signed<Num>::value, "Num must be signed");

static Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { // a < a2, c < c2
return a == c ? std::min(a2, c2) : a2 <= c ? a2 : c2 <= a ? c2 : std::max(a, c);
}

struct S {
Num lo, lo2, sum;
unsigned sz, nlo;
bool fail;
S() : lo(INF), lo2(INF), sum(0), sz(0), nlo(0), fail(false) {}
S(Num x, unsigned sz_ = 1)
: lo(x), lo2(INF), sum(Num(x) * sz_), sz(sz_), nlo(sz_), fail(false) {}
};

private:
static S e() { return S(); }

static S op(S l, S r) {
S ret;
ret.lo = std::min(l.lo, r.lo);
ret.lo2 = second_lowest(l.lo, l.lo2, r.lo, r.lo2);
ret.sum = l.sum + r.sum, ret.sz = l.sz + r.sz;
ret.nlo = l.nlo * (l.lo <= r.lo) + r.nlo * (r.lo <= l.lo);
return ret;
}

struct F {
Num lb, bias;
F() : lb(-INF), bias(0) {}
F(Num chmax_, Num add) : lb(chmax_), bias(add) {}
};

static F id() { return F(); }

static S mapping(F f, S x) {
if (x.sz == 0) return e();
if (f.lb < x.lo2) {
Num nxt_lo = std::max(x.lo, f.lb);
x.sum += (nxt_lo - x.lo) * x.nlo + f.bias * x.sz;
x.lo = nxt_lo + f.bias, x.lo2 += f.bias;
return x;
}
x.fail = 1;
return x;
}

public:
static F composition(F fnew, F fold) {
F ret;
ret.lb = std::max(fold.lb + fold.bias, fnew.lb) - fold.bias;
ret.bias = fold.bias + fnew.bias;
return ret;
}

static F Chmax(Num x) noexcept { return F(x, Num(0)); }
static F Add(Num x) noexcept { return F(-INF, x); };

static S Gen(Num x, unsigned sz = 1) { return S{x, sz}; }

using segtree = segtree_beats<S, op, e, F, mapping, composition, id>;
};
/* Usage:
using RCARS = RangeChmaxAddRangeSum<long long, (1LL << 60)>;
vector<RCARS::S> init;
for (auto a : A) init.push_back(RCARS::Gen(a, 1));
RCARS::segtree tree(init);

tree.apply(l, r, RCARS::Chmax(x));
tree.apply(l, r, RCARS::Add(x));
auto p = tree.prod(l, r);
*/
Loading