Skip to content

Commit 3a14350

Browse files
committed
Use bitset in fenwick_set
1 parent 82e0d01 commit 3a14350

File tree

2 files changed

+49
-21
lines changed

2 files changed

+49
-21
lines changed

cp-algo/structures/fenwick.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,17 @@ namespace cp_algo::structures {
4242
T range_sum(size_t l, size_t r) const {
4343
return prefix_sum(r) - prefix_sum(l);
4444
}
45-
// First r s.t. prefix_sum(r) >= k
45+
// First r s.t. prefix_sum(r) > k
4646
// Assumes data[x] >= 0 for all x
47-
size_t prefix_lower_bound(T k) const {
47+
auto prefix_lower_bound(T k) const {
4848
int x = 0;
4949
for(size_t i = std::bit_floor(n); i; i /= 2) {
5050
if(x + i <= n && data[x + i] < k) {
5151
k -= data[x + i];
5252
x += i;
5353
}
5454
}
55-
return x;
55+
return std::pair{x, k};
5656
}
5757
};
5858
}

cp-algo/structures/fenwick_set.hpp

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,76 @@
11
#ifndef CP_ALGO_STRUCTURES_FENWICK_SET_HPP
22
#define CP_ALGO_STRUCTURES_FENWICK_SET_HPP
33
#include "fenwick.hpp"
4+
#include <immintrin.h>
5+
#include <cstdint>
46
#include <bitset>
57
namespace cp_algo::structures {
68
// fenwick-based set for [0, maxc)
7-
template<size_t maxc>
8-
struct fenwick_set: fenwick<int, std::array<int, maxc+1>> {
9-
using Base = fenwick<int, std::array<int, maxc+1>>;
9+
// Requires GCC target("popcnt,bmi2")
10+
template<typename Uint>
11+
constexpr size_t width = sizeof(Uint) * 8;
12+
template<size_t maxc, typename Uint>
13+
using popcount_array = std::array<int, maxc / width<Uint> + 1>;
14+
template<size_t maxc, typename Uint = uint64_t>
15+
struct fenwick_set: fenwick<int, popcount_array<maxc, Uint>> {
16+
using Base = fenwick<int, popcount_array<maxc, Uint>>;
17+
static constexpr size_t word = width<Uint>;
1018
size_t sz = 0;
11-
std::bitset<maxc> present;
12-
fenwick_set(): Base(std::array<int, maxc+1>()) {}
19+
std::array<Uint, maxc / word + 1> bits;
20+
21+
void flip_bit(size_t x) {
22+
bits[x / word] ^= 1ULL << (x % word);
23+
}
24+
bool present(size_t x) const {
25+
return (bits[x / word] >> (x % word)) & 1;
26+
}
27+
28+
fenwick_set(): Base(popcount_array<maxc, Uint>{}) {}
1329
fenwick_set(auto &&range): fenwick_set() {
1430
for(auto x: range) {
15-
Base::data[x + 1] = 1;
16-
sz += !present[x];
17-
present[x] = 1;
31+
Base::data[x / word + 1] += 1;
32+
if(!present(x)) {
33+
sz++;
34+
flip_bit(x);
35+
}
1836
}
1937
Base::to_prefix_sums();
2038
}
2139
void insert(size_t x) {
22-
if(present[x]) return;
23-
present[x] = 1;
40+
if(present(x)) return;
41+
flip_bit(x);
2442
sz++;
25-
Base::add(x, 1);
43+
Base::add(x / word, 1);
2644
}
2745
void erase(size_t x) {
28-
if(!present[x]) return;
29-
present[x] = 0;
46+
if(!present(x)) return;
47+
flip_bit(x);
3048
sz--;
31-
Base::add(x, -1);
49+
Base::add(x / word, -1);
50+
}
51+
static size_t order_of_bit(Uint x, size_t k) {
52+
return k ? std::popcount(x << (word - k)) : 0;
3253
}
3354
size_t order_of_key(size_t x) const {
34-
return Base::prefix_sum(x);
55+
return Base::prefix_sum(x / word) + order_of_bit(bits[x / word], x % word);
56+
}
57+
static size_t kth_set_bit(Uint x, size_t k) {
58+
return std::countr_zero(_pdep_u64(1ULL << k, x));
3559
}
3660
size_t find_by_order(size_t order) const {
37-
return order < sz ? Base::prefix_lower_bound(order + 1) : -1;
61+
if(order >= sz) {
62+
return -1;
63+
}
64+
auto [x, remainder] = Base::prefix_lower_bound(order + 1);
65+
return x * word + kth_set_bit(bits[x], remainder - 1);
3866
}
3967
size_t lower_bound(size_t x) const {
40-
if(present[x]) {return x;}
68+
if(present(x)) {return x;}
4169
auto order = order_of_key(x);
4270
return order < sz ? find_by_order(order) : -1;
4371
}
4472
size_t pre_upper_bound(size_t x) const {
45-
if(present[x]) {return x;}
73+
if(present(x)) {return x;}
4674
auto order = order_of_key(x);
4775
return order ? find_by_order(order - 1) : -1;
4876
}

0 commit comments

Comments
 (0)