Skip to content

Commit 66bfb35

Browse files
committed
Support any operations in Fenwick
1 parent f6f706d commit 66bfb35

File tree

5 files changed

+119
-30
lines changed

5 files changed

+119
-30
lines changed

cp-algo/structures/fenwick.hpp

+57-21
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,92 @@
33
#include <cassert>
44
#include <vector>
55
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>>
724
struct fenwick {
25+
Op op;
826
size_t n;
927
Container data;
1028

11-
fenwick(auto &&range) {
12-
assign(move(range));
29+
fenwick(auto &&range, Op &&op = Op{}): op(std::move(op)) {
30+
assign(std::move(range));
1331
}
14-
void to_prefix_sums() {
32+
void to_prefix_folds() {
1533
for(size_t i = 1; i < n; i++) {
1634
if(i + (i & -i) <= n) {
17-
data[i + (i & -i)] += data[i];
35+
data[i + (i & -i)] = op(data[i + (i & -i)], data[i]);
1836
}
1937
}
2038
}
2139
void assign(auto &&range) {
2240
n = size(range) - 1;
23-
data = move(range);
24-
to_prefix_sums();
41+
data = std::move(range);
42+
to_prefix_folds();
2543
}
26-
void add(size_t x, T const& v) {
44+
void update(size_t x, T const& v) {
2745
for(++x; x <= n; x += x & -x) {
28-
data[x] += v;
46+
data[x] = op(data[x], v);
2947
}
3048
}
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 {
3351
assert(r <= n);
34-
T res = 0;
52+
T res = {};
3553
for(; r; r -= r & -r) {
36-
res += data[r];
54+
res = op(res, data[r]);
3755
}
3856
return res;
3957
}
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));
4361
}
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)]
4665
auto prefix_lower_bound(T k) const {
4766
int x = 0;
67+
T pref = {};
4868
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]);
5171
x += i;
5272
}
5373
}
54-
return std::pair{x, k};
74+
return std::pair{x, pref};
5575
}
5676
};
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+
5793
}
5894
#endif // CP_ALGO_STRUCTURES_FENWICK_HPP

cp-algo/structures/fenwick_set.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,29 @@ namespace cp_algo::structures {
2222
bits.flip(x);
2323
}
2424
}
25-
Base::to_prefix_sums();
25+
Base::to_prefix_folds();
2626
}
2727
void insert(size_t x) {
2828
if(bits.test(x)) return;
29-
Base::add(x / word, 1);
29+
Base::update(x / word, 1);
3030
bits.flip(x);
3131
sz++;
3232
}
3333
void erase(size_t x) {
3434
if(!bits.test(x)) return;
35-
Base::add(x / word, -1);
35+
Base::update(x / word, -1);
3636
bits.flip(x);
3737
sz--;
3838
}
3939
size_t order_of_key(size_t x) const {
40-
return Base::prefix_sum(x / word) + order_of_bit(bits.word(x / word), x % word);
40+
return Base::prefix_fold(x / word) + order_of_bit(bits.word(x / word), x % word);
4141
}
4242
size_t find_by_order(size_t order) const {
4343
if(order >= sz) {
4444
return -1;
4545
}
46-
auto [x, remainder] = Base::prefix_lower_bound(order + 1);
47-
return x * word + kth_set_bit(bits.word(x), remainder - 1);
46+
auto [x, pref] = Base::prefix_lower_bound(order);
47+
return x * word + kth_set_bit(bits.word(x), order - pref);
4848
}
4949
size_t lower_bound(size_t x) const {
5050
if(bits.test(x)) {return x;}

cp-algo/util/compress_coords.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <vector>
55
namespace cp_algo {
66
// coords is a range of reference_wrapper<T>
7-
auto compress_coords(auto &coords) {
7+
auto compress_coords(auto &&coords) {
88
using T = std::decay_t<std::unwrap_reference_t<
99
std::ranges::range_value_t<decltype(coords)>
1010
>>;
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// @brief Longest Increasing Subsequence
2+
#define PROBLEM "https://judge.yosupo.jp/problem/longest_increasing_subsequence"
3+
#pragma GCC optimize("Ofast,unroll-loops")
4+
#include "cp-algo/structures/fenwick.hpp"
5+
#include "cp-algo/util/compress_coords.hpp"
6+
#include <bits/stdc++.h>
7+
8+
using namespace std;
9+
10+
void solve() {
11+
int n;
12+
cin >> n;
13+
vector<reference_wrapper<int>> coords;
14+
vector<int> a(n);
15+
for(auto &it: a) {
16+
cin >> it;
17+
coords.push_back(ref(it));
18+
}
19+
auto b = cp_algo::compress_coords(coords);
20+
struct longest {
21+
int len = 0, last = 0;
22+
auto operator <=>(longest const&) const = default;
23+
};
24+
cp_algo::structures::fenwick_max me(vector<longest>(n + 1));
25+
vector<int> pre(n);
26+
for(auto [i, it]: a | views::enumerate) {
27+
auto [len, last] = me.prefix_fold(it);
28+
me.update(it, {len + 1, (int)i});
29+
pre[i] = last;
30+
}
31+
auto [len, last] = me.prefix_fold(n);
32+
cout << len << '\n';
33+
vector<int> ans(len);
34+
while(len--) {
35+
ans[len] = last;
36+
last = pre[last];
37+
}
38+
for(auto it: ans) {
39+
cout << it << ' ';
40+
}
41+
}
42+
43+
signed main() {
44+
//freopen("input.txt", "r", stdin);
45+
ios::sync_with_stdio(0);
46+
cin.tie(0);
47+
int t;
48+
t = 1;// cin >> t;
49+
while(t--) {
50+
solve();
51+
}
52+
}
53+

verify/structures/fenwick/point_add_range_sum.test.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ void solve() {
1111
cin >> n >> q;
1212
vector<int64_t> a(n + 1);
1313
for(auto &it: a | views::drop(1)) {cin >> it;}
14-
cp_algo::structures::fenwick<int64_t> me(move(a));
14+
cp_algo::structures::fenwick me(move(a));
1515
for(int i = 0; i < q; i++) {
1616
int t, x, y;
1717
cin >> t >> x >> y;
1818
if(t == 0) {
1919
me.add(x, y);
2020
} else {
21-
cout << me.range_sum(x, y) << '\n';
21+
cout << me.range_fold(x, y) << '\n';
2222
}
2323
}
2424
}

0 commit comments

Comments
 (0)