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
34 changes: 24 additions & 10 deletions segmenttree/acl_beats.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#pragma once
#include "acl_lazysegtree.hpp"

// CUT begin
template <class S, S (*op)(S, S), S (*e)(), class F, S (*mapping)(F, S), F (*composition)(F, F),
F (*id)()>
class segtree_beats : public atcoder::lazy_segtree<S, op, e, F, mapping, composition, id> {
Expand All @@ -19,12 +18,14 @@ class segtree_beats : public atcoder::lazy_segtree<S, op, e, F, mapping, composi
namespace RangeChMinMaxAddSum {
#include <algorithm>

template <typename Num>
inline Num second_lowest(Num a, Num a2, Num c, Num c2) noexcept { // a < a2, c < c2
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 { // a > a2, b > b2
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);
}

Expand All @@ -36,7 +37,7 @@ struct S {
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_ = 1)
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
Expand All @@ -49,10 +50,12 @@ 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.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.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;
Expand All @@ -76,21 +79,32 @@ F composition(F fnew, F fold) {
F id() { return F(); }
S mapping(F f, S x) {
if (x.sz == 0) return e();
if (x.lo == x.hi or f.lb == f.ub or f.lb >= x.hi or f.ub < x.lo)

// 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.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
92 changes: 92 additions & 0 deletions segmenttree/test/beats_random_test.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#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 <algorithm>
#include <cstdio>
#include <numeric>
#include <vector>

using RangeChMinMaxAddSum::S, RangeChMinMaxAddSum::F;

int main() {
for (int trial = 0; trial < 1 << 20; ++trial) {
const int N = rand_int() % 32 + 1;

const int maxA = rand_int() % 50 + 1;
const int Q = rand_int() % 10 + 1;

std::vector<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);
}

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

for (int q = 0; q < Q; ++q) {
int tp = rand_int() % 4;
if (q == Q - 1) tp = 3;

int l = 0, r = 0;
while (l == r) {
l = rand_int() % (N + 1);
r = rand_int() % (N + 1);
if (l > r) std::swap(l, r);
}

if (tp < 3) {
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));
}

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));
}

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

if (tp == 3) {
auto prod = segtree.prod(l, r);

std::vector<int> values;
for (int i = l; i < r; ++i) values.push_back(simulate.at(i));
std::sort(values.begin(), values.end());

assert(prod.lo == values.front());
assert(prod.nlo == std::count(values.begin(), values.end(), prod.lo));

assert(prod.hi == values.back());
assert(prod.nhi == std::count(values.begin(), values.end(), prod.hi));

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

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

if (values.front() != values.back()) {
int i = 0;
while (values.at(i) == values.front()) ++i;
assert(prod.lo2 == values.at(i));

i = (int)values.size() - 1;
while (values.at(i) == values.back()) --i;
assert(prod.hi2 == values.at(i));
}
}
}
}

puts("Hello World");
}
10 changes: 6 additions & 4 deletions segmenttree/trees/acl_range-update-gcd-range-max-sum.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once
#include "../acl_beats.hpp"

// CUT begin
#include <cstdint>
#include <numeric>

// Verified: https://yukicoder.me/submissions/611774
namespace yuki880 {
constexpr uint32_t BINF = 1 << 30;
Expand All @@ -28,7 +30,7 @@ S op(S l, S r) {
ret.sum = l.sum + r.sum;
ret.lcm = (l.lcm >= BINF or r.lcm >= BINF)
? BINF
: std::min<uint64_t>(BINF, (uint64_t)l.lcm * r.lcm / std::__gcd(l.lcm, r.lcm));
: std::min<uint64_t>(BINF, (uint64_t)l.lcm * r.lcm / std::gcd(l.lcm, r.lcm));
ret.sz = l.sz + r.sz;
if (l.all_same and r.all_same and l.max == r.max) ret.all_same = true;
return ret;
Expand All @@ -43,7 +45,7 @@ struct F {
};

F composition(F fnew, F fold) {
return fnew.reset ? fnew : F(std::__gcd(fnew.dogcd, fold.dogcd), fold.reset);
return fnew.reset ? fnew : F(std::gcd(fnew.dogcd, fold.dogcd), fold.reset);
}

F id() { return F(); }
Expand All @@ -53,7 +55,7 @@ S mapping(F f, S x) {
if (f.reset) x = S(f.reset, x.sz);
if (f.dogcd) {
if (x.all_same)
x = S(std::__gcd(f.dogcd, x.max), x.sz);
x = S(std::gcd(f.dogcd, x.max), x.sz);
else if (f.dogcd and (x.lcm == BINF or f.dogcd % x.lcm))
x.fail = true;
}
Expand Down