|
3 | 3 | #include <cassert>
|
4 | 4 | #include <vector>
|
5 | 5 | namespace cp_algo::structures {
|
6 |
| - template<typename T, typename Container = std::vector<T>> |
| 6 | + template <typename Op> |
| 7 | + struct inverse_op {}; |
| 8 | + |
| 9 | + template <typename T> |
| 10 | + struct inverse_op<std::plus<T>> { |
| 11 | + static T apply(T const& a, T const& b) { |
| 12 | + return a - b; |
| 13 | + } |
| 14 | + }; |
| 15 | + |
| 16 | + template <typename T> |
| 17 | + struct inverse_op<std::multiplies<T>> { |
| 18 | + static T apply(T const& a, T const& b) { |
| 19 | + return a / b; |
| 20 | + } |
| 21 | + }; |
| 22 | + |
| 23 | + template<typename T, std::ranges::range Container = std::vector<T>, typename Op = std::plus<T>> |
7 | 24 | struct fenwick {
|
| 25 | + Op op; |
8 | 26 | size_t n;
|
9 | 27 | Container data;
|
10 | 28 |
|
11 |
| - fenwick(auto &&range) { |
12 |
| - assign(move(range)); |
| 29 | + fenwick(auto &&range, Op &&op = Op{}): op(std::move(op)) { |
| 30 | + assign(std::move(range)); |
13 | 31 | }
|
14 |
| - void to_prefix_sums() { |
| 32 | + void to_prefix_folds() { |
15 | 33 | for(size_t i = 1; i < n; i++) {
|
16 | 34 | if(i + (i & -i) <= n) {
|
17 |
| - data[i + (i & -i)] += data[i]; |
| 35 | + data[i + (i & -i)] = op(data[i + (i & -i)], data[i]); |
18 | 36 | }
|
19 | 37 | }
|
20 | 38 | }
|
21 | 39 | void assign(auto &&range) {
|
22 | 40 | n = size(range) - 1;
|
23 |
| - data = move(range); |
24 |
| - to_prefix_sums(); |
| 41 | + data = std::move(range); |
| 42 | + to_prefix_folds(); |
25 | 43 | }
|
26 |
| - void add(size_t x, T const& v) { |
| 44 | + void update(size_t x, T const& v) { |
27 | 45 | for(++x; x <= n; x += x & -x) {
|
28 |
| - data[x] += v; |
| 46 | + data[x] = op(data[x], v); |
29 | 47 | }
|
30 | 48 | }
|
31 |
| - // sum of [0, r) |
32 |
| - T prefix_sum(size_t r) const { |
| 49 | + // fold of [0, r) |
| 50 | + T prefix_fold(size_t r) const { |
33 | 51 | assert(r <= n);
|
34 |
| - T res = 0; |
| 52 | + T res = {}; |
35 | 53 | for(; r; r -= r & -r) {
|
36 |
| - res += data[r]; |
| 54 | + res = op(res, data[r]); |
37 | 55 | }
|
38 | 56 | return res;
|
39 | 57 | }
|
40 |
| - // sum of [l, r) |
41 |
| - T range_sum(size_t l, size_t r) const { |
42 |
| - return prefix_sum(r) - prefix_sum(l); |
| 58 | + // fold of [l, r) |
| 59 | + T range_fold(size_t l, size_t r) const { |
| 60 | + return inverse_op<Op>::apply(prefix_fold(r), prefix_fold(l)); |
43 | 61 | }
|
44 |
| - // Last x s.t. k = prefix_sum(x) + r for r > 0 |
45 |
| - // Assumes data[x] >= 0 for all x, returns [x, r] |
| 62 | + // Last x s.t. prefix_fold(x) <= k |
| 63 | + // Assumes prefix_fold is monotonic |
| 64 | + // returns [x, prefix_fold(x)] |
46 | 65 | auto prefix_lower_bound(T k) const {
|
47 | 66 | int x = 0;
|
| 67 | + T pref = {}; |
48 | 68 | for(size_t i = std::bit_floor(n); i; i /= 2) {
|
49 |
| - if(x + i <= n && data[x + i] < k) { |
50 |
| - k -= data[x + i]; |
| 69 | + if(x + i <= n && op(pref, data[x + i]) <= k) { |
| 70 | + pref = op(pref, data[x + i]); |
51 | 71 | x += i;
|
52 | 72 | }
|
53 | 73 | }
|
54 |
| - return std::pair{x, k}; |
| 74 | + return std::pair{x, pref}; |
55 | 75 | }
|
56 | 76 | };
|
| 77 | + |
| 78 | + template<std::ranges::range Container, typename Op> |
| 79 | + fenwick(Container&&, Op&&) -> fenwick<std::ranges::range_value_t<Container>, Container, Op>; |
| 80 | + template<std::ranges::range Container> |
| 81 | + fenwick(Container&&) -> fenwick<std::ranges::range_value_t<Container>, Container>; |
| 82 | + |
| 83 | + auto maxer = [](auto const& a, auto const& b) { |
| 84 | + return std::max(a, b); |
| 85 | + }; |
| 86 | + template<typename T, std::ranges::range Container = std::vector<T>> |
| 87 | + struct fenwick_max: fenwick<T, Container, decltype(maxer)> { |
| 88 | + using fenwick<T, Container, decltype(maxer)>::fenwick; |
| 89 | + }; |
| 90 | + template<std::ranges::range Container> |
| 91 | + fenwick_max(Container&&) -> fenwick_max<std::ranges::range_value_t<Container>, Container>; |
| 92 | + |
57 | 93 | }
|
58 | 94 | #endif // CP_ALGO_STRUCTURES_FENWICK_HPP
|
0 commit comments