|
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