cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
bit_trie.hpp
1#pragma once
2
3#include <algorithm>
4#include <array>
5#include <cstdint>
6#include <memory>
7#include <optional>
8#include <utility>
9#include <variant>
10#include <vector>
11
12#include "cplib/utils/bit.hpp"
13
14namespace cplib {
15
31template <typename T, int Bits, int Offset>
33 public:
34 using Child = StaticSizedBitTrie<T, Bits, Offset - Bits>;
35 using bitmap_t = uint64_t;
36 using size_type = std::size_t;
37 static constexpr int branch_mask = (1 << Bits) - 1;
38
40 StaticSizedBitTrie() : size_(0), bitmap(0) {}
41
43 size_type size() const { return size_; }
44
46 bool empty() const { return size_ == 0; }
47
49 bool insert(T val) {
50 int idx = (val >> Offset) & branch_mask;
51 size_type pos = impl::popcount_low(bitmap, idx);
52 if (!((bitmap >> idx) & 1)) {
53 bitmap |= bitmap_t(1) << idx;
54 children.emplace(children.begin() + pos);
55 }
56 bool ret = children[pos].insert(val);
57 size_ += ret;
58 return ret;
59 }
60
62 bool erase(T val) {
63 int idx = (val >> Offset) & branch_mask;
64 if ((bitmap >> idx) & 1) {
65 size_type pos = impl::popcount_low(bitmap, idx);
66 bool ret = children[pos].erase(val);
67 size_ -= ret;
68 if (children[pos].empty()) {
69 bitmap &= ~(bitmap_t(1) << idx);
70 children.erase(children.begin() + pos);
71 }
72 return ret;
73 } else {
74 return false;
75 }
76 }
77
79 bool find(T val) const {
80 int idx = (val >> Offset) & branch_mask;
81 if ((bitmap >> idx) & 1) {
82 size_type pos = impl::popcount_low(bitmap, idx);
83 return children[pos].find(val);
84 } else {
85 return false;
86 }
87 }
88
96 T xor_min(T xor_val) const {
97 int curr_xor_val = (xor_val >> Offset) & branch_mask;
98 int curr_xor_min = port::countr_zero(impl::xor_permute(bitmap, curr_xor_val));
99 size_type pos = impl::popcount_low(bitmap, curr_xor_min ^ curr_xor_val);
100 return (T(curr_xor_min) << Offset) | children[pos].xor_min(xor_val);
101 }
102
104 std::optional<T> next(T val) const {
105 int idx = (val >> Offset) & branch_mask;
106 int next_idx = impl::next_set_bit(bitmap, idx);
107 if (next_idx == 64) {
108 return std::nullopt;
109 } else {
110 size_type pos = impl::popcount_low(bitmap, next_idx);
111 if (next_idx > idx) {
112 return (T(next_idx) << Offset) | *(children[pos].next(0));
113 }
114 auto ret = children[pos].next(val);
115 if (ret) {
116 return (T(next_idx) << Offset) | *ret;
117 }
118 next_idx = impl::next_set_bit(bitmap, next_idx + 1);
119 if (next_idx == 64) {
120 return std::nullopt;
121 } else {
122 return (T(next_idx) << Offset) | *(children[pos + 1].next(0));
123 }
124 }
125 }
126
128 std::optional<T> prev(T val) const {
129 int idx = (val >> Offset) & branch_mask;
130 int prev_idx = impl::prev_set_bit(bitmap, idx + 1);
131 if (prev_idx == -1) {
132 return std::nullopt;
133 } else {
134 size_type pos = impl::popcount_low(bitmap, prev_idx);
135 constexpr T MAX = (T(1) << Offset) - 1;
136 if (prev_idx < idx) {
137 return (T(prev_idx) << Offset) | *(children[pos].prev(MAX));
138 }
139 auto ret = children[pos].prev(val);
140 if (ret) {
141 return (T(prev_idx) << Offset) | *ret;
142 }
143 prev_idx = impl::prev_set_bit(bitmap, prev_idx);
144 if (prev_idx == -1) {
145 return std::nullopt;
146 } else {
147 return (T(prev_idx) << Offset) | *(children[pos - 1].prev(MAX));
148 }
149 }
150 }
151
152 private:
153 bitmap_t bitmap;
154 size_type size_;
155 std::vector<Child> children;
156};
157
159template <typename T, int Bits>
160class StaticSizedBitTrie<T, Bits, 0> {
161 public:
162 using bitmap_t = uint64_t;
163 using size_type = std::size_t;
164 static constexpr int branch_mask = (1 << Bits) - 1;
165
166 StaticSizedBitTrie() : bitmap(0) {}
167
168 size_type size() const { return port::popcount(bitmap); }
169
170 bool empty() const { return bitmap == 0; }
171
172 bool insert(T val) {
173 int idx = val & branch_mask;
174 bool ret = !((bitmap >> idx) & 1);
175 bitmap |= bitmap_t(1) << idx;
176 return ret;
177 }
178
179 bool erase(T val) {
180 int idx = val & branch_mask;
181 bool ret = (bitmap >> idx) & 1;
182 bitmap &= ~(bitmap_t(1) << idx);
183 return ret;
184 }
185
186 bool find(T val) const { return (bitmap >> (val & branch_mask)) & 1; }
187
188 T xor_min(T xor_val) const { return port::countr_zero(impl::xor_permute(bitmap, xor_val & branch_mask)); }
189
190 std::optional<T> next(T val) const {
191 int ret = impl::next_set_bit(bitmap, val & branch_mask);
192 return ret == 64 ? std::nullopt : std::make_optional(ret);
193 }
194
195 std::optional<T> prev(T val) const {
196 int ret = impl::prev_set_bit(bitmap, (val & branch_mask) + 1);
197 return ret == -1 ? std::nullopt : std::make_optional(ret);
198 }
199
200 private:
201 bitmap_t bitmap;
202};
203
210template <typename T, int U>
211using BitTrie = StaticSizedBitTrie<T, 6, (U - 1) / 6 * 6>;
212
213} // namespace cplib
Bit trie that manages an ordered set of integers, with compile-time fixed height.
Definition: bit_trie.hpp:32
bool insert(T val)
Insert an elemnent. Returns whether the element is inserted (i.e. doesn't exist before insertion).
Definition: bit_trie.hpp:49
std::optional< T > prev(T val) const
Returns the largest element no larger than the given value, or std::nullopt if it doesn't exist,...
Definition: bit_trie.hpp:128
bool find(T val) const
Returns whether the element exists.
Definition: bit_trie.hpp:79
size_type size() const
Returns the number of elements.
Definition: bit_trie.hpp:43
std::optional< T > next(T val) const
Returns the smallest element no smaller than the given value, or std::nullopt if it doesn't exist.
Definition: bit_trie.hpp:104
bool erase(T val)
Delete an elemnent. Returns whether the element is deleted (i.e. exists before deletion).
Definition: bit_trie.hpp:62
bool empty() const
Returns whether the trie is empty.
Definition: bit_trie.hpp:46
StaticSizedBitTrie()
Creates an empty trie.
Definition: bit_trie.hpp:40
T xor_min(T xor_val) const
Returns the minimum of any element xor the give value.
Definition: bit_trie.hpp:96