digest
Loading...
Searching...
No Matches
data_structure.hpp
1#ifndef DATA_STRUCTURE_HPP
2#define DATA_STRUCTURE_HPP
3
4#include <algorithm>
5#include <array>
6#include <cmath>
7#include <cstdint>
8#include <stdint.h>
9#include <type_traits>
10#include <utility>
11#include <vector>
12
27namespace digest::ds {
28
33template <typename T> struct Interface {
34 static_assert(std::is_same<T, uint32_t>() || std::is_same<T, uint64_t>(),
35 "T must be either uint32_t or uint64_t");
36
38 Interface(uint32_t);
39
41 virtual uint32_t min();
43 virtual T min_hash();
44
46 virtual void min_syncmer(std::vector<uint32_t> &vec);
48 virtual void min_syncmer(std::vector<std::pair<uint32_t, T>> &vec);
49};
50
51// Based on a template taken from USACO.guide and then modified by me (for
52// competitive programming), and now modified again (for this)
53// https://usaco.guide/gold/PURS?lang=cpp
54// https://codeforces.com/blog/entry/18051 (USACO.guide was probably heavily
55// inspired by this)
64template <int k> struct SegmentTree {
65 int i = k;
66 std::array<uint64_t, 2 * k> segtree = {};
67
68 constexpr int log2() { return std::ceil(std::log2(k)); }
69
70 SegmentTree(uint32_t) {}
71 SegmentTree(const SegmentTree &other) = default;
72 SegmentTree &operator=(const SegmentTree &other) = default;
73
74 void insert(uint32_t index, uint32_t hash) {
75 int ind = i;
76 if (++i == 2 * k)
77 i = k;
78
79 // negate so we can use max so that ties are broken by rightmost
80 segtree[ind] = (uint64_t)~hash << 32 | index;
81 for (int rep = 0; rep < log2(); rep++) {
82 segtree[ind >> 1] = std::max(segtree[ind], segtree[ind ^ 1]);
83 ind >>= 1;
84 }
85 }
86
87 uint32_t min() { return segtree[1]; }
88
89 uint32_t min_hash() { return ~(segtree[1] >> 32); }
90
91 void min_syncmer(std::vector<uint32_t> &vec) {
92 if (segtree[1] >> 32 ==
93 std::max(uint32_t(segtree[i] >> 32),
94 uint32_t(segtree[i == k ? 2 * k - 1 : i - 1] >> 32))) {
95 vec.emplace_back(segtree[i]);
96 }
97 }
98
99 void min_syncmer(std::vector<std::pair<uint32_t, uint32_t>> &vec) {
100 if (segtree[1] >> 32 ==
101 std::max(uint32_t(segtree[i] >> 32),
102 uint32_t(segtree[i == k ? 2 * k - 1 : i - 1] >> 32))) {
103 vec.emplace_back(segtree[i], ~(segtree[1] >> 32));
104 }
105 }
106};
107
114template <uint32_t k> struct Naive {
115 std::array<uint64_t, k> arr;
116 unsigned int i = 0;
117
118 Naive(uint32_t){};
119 Naive(const Naive &other) = default;
120 Naive &operator=(const Naive &other) = default;
121
122 void insert(uint32_t index, uint32_t hash) {
123 arr[i] = (uint64_t)~hash << 32 | index;
124 if (++i == k)
125 i = 0;
126 }
127
128 uint32_t min() {
129 int i = k - 1;
130 for (int j = k - 2; j >= 0; j--) {
131 if (arr[j] > arr[i]) {
132 i = j;
133 }
134 }
135 return arr[i];
136 }
137
138 uint32_t min_hash() {
139 int i = k - 1;
140 for (int j = k - 2; j >= 0; j--) {
141 if (arr[j] > arr[i]) {
142 i = j;
143 }
144 }
145 return ~(uint32_t)(arr[i] >> 32);
146 }
147
148 void min_syncmer(std::vector<uint32_t> &vec) {
149 unsigned int j = 0;
150 for (unsigned int l = 1; l < k; l++) {
151 if (arr[l] > arr[j]) {
152 j = l;
153 }
154 }
155 if (arr[j] >> 32 == std::max(uint32_t(arr[i] >> 32),
156 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
157 vec.emplace_back(arr[i]);
158 }
159 }
160
161 void min_syncmer(std::vector<std::pair<uint32_t, uint32_t>> &vec) {
162 unsigned int j = k - 1;
163 for (int l = k - 2; l >= 0; l--) {
164 if (arr[l] > arr[j]) {
165 j = l;
166 }
167 }
168 if (arr[j] >> 32 == std::max(uint32_t(arr[i] >> 32),
169 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
170 vec.emplace_back(arr[i], ~(uint32_t)(arr[j] >> 32));
171 }
172 }
173};
174
181template <uint32_t k> struct Naive2 {
182 unsigned int i = 0;
183 unsigned int last = 0;
184 std::vector<uint64_t> arr = std::vector<uint64_t>(k);
185
186 Naive2(uint32_t){};
187 Naive2(const Naive2 &other) = default;
188 Naive2 &operator=(const Naive2 &other) = default;
189
190 void insert(uint32_t index, uint32_t hash) {
191 // flip the hash bits so we can take the maximum
192 arr[i] = (uint64_t)~hash << 32 | index;
193
194 if (arr[i] > arr[last]) {
195 last = i;
196 } else if (last == i) {
197 for (unsigned j = 0; j < k; j++) {
198 if (arr[j] > arr[last]) {
199 last = j;
200 }
201 }
202 }
203
204 if (++i == k)
205 i = 0;
206 }
207
208 uint32_t min() { return arr[last]; }
209
210 uint32_t min_hash() { return ~(uint32_t)(arr[last] >> 32); }
211
212 void min_syncmer(std::vector<uint32_t> &vec) {
213 if (arr[last] >> 32 ==
214 std::max(uint32_t(arr[i] >> 32),
215 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
216 vec.emplace_back(arr[i]);
217 }
218 }
219
220 void min_syncmer(std::vector<std::pair<uint32_t, uint32_t>> &vec) {
221 if (arr[last] >> 32 ==
222 std::max(uint32_t(arr[i] >> 32),
223 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
224 vec.emplace_back(arr[i], ~(uint32_t)(arr[last] >> 32));
225 }
226 }
227};
228
233struct Adaptive {
234 uint32_t k, i = 0, last = 0;
235 std::vector<uint64_t> arr;
236
237 Adaptive(uint32_t k) : k(k), arr(k) {}
238 Adaptive(const Adaptive &other) = default;
239 Adaptive &operator=(const Adaptive &other) = default;
240
241 void naive(uint32_t index, uint32_t hash) {
242 arr[i] = (uint64_t)~hash << 32 | index;
243 if (++i == k)
244 i = 0;
245 }
246
247 void naive2(uint32_t index, uint32_t hash) {
248 // flip the hash bits so we can take the maximum
249 arr[i] = (uint64_t)~hash << 32 | index;
250
251 if (arr[i] > arr[last]) {
252 last = i;
253 } else if (last == i) {
254 for (unsigned j = 0; j < k; j++) {
255 if (arr[j] > arr[last]) {
256 last = j;
257 }
258 }
259 }
260
261 if (++i == k)
262 i = 0;
263 }
264
265 void insert(uint32_t index, uint32_t hash) {
266 if (k < 16) {
267 naive(index, hash);
268 } else {
269 naive2(index, hash);
270 }
271 }
272
273 uint32_t min() {
274 if (k < 16) {
275 int i = k - 1;
276 for (int j = k - 2; j >= 0; j--) {
277 if (arr[j] > arr[i]) {
278 i = j;
279 }
280 }
281 return arr[i];
282 } else {
283 return arr[last];
284 }
285 }
286
287 uint32_t min_hash() {
288 if (k < 16) {
289 int i = k - 1;
290 for (int j = k - 2; j >= 0; j--) {
291 if (arr[j] > arr[i]) {
292 i = j;
293 }
294 }
295 return ~(uint32_t)(arr[i] >> 32);
296 } else {
297 return ~(uint32_t)(arr[last] >> 32);
298 }
299 }
300
301 void min_syncmer(std::vector<uint32_t> &vec) {
302 if (k < 16) {
303 unsigned int j = k - 1;
304 for (int l = k - 2; l >= 0; l--) {
305 if (arr[l] > arr[j]) {
306 j = l;
307 }
308 }
309 if (arr[j] >> 32 ==
310 std::max(uint32_t(arr[i] >> 32),
311 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
312 vec.emplace_back(arr[i]);
313 }
314 } else {
315 if (arr[last] >> 32 ==
316 std::max(uint32_t(arr[i] >> 32),
317 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
318 vec.emplace_back(arr[i]);
319 }
320 }
321 }
322
323 void min_syncmer(std::vector<std::pair<uint32_t, uint32_t>> &vec) {
324 if (k < 16) {
325 unsigned int j = k - 1;
326 for (int l = k - 2; l >= 0; l--) {
327 if (arr[l] > arr[j]) {
328 j = l;
329 }
330 }
331 if (arr[j] >> 32 ==
332 std::max(uint32_t(arr[i] >> 32),
333 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
334 vec.emplace_back(arr[i], ~(uint32_t)(arr[j] >> 32));
335 }
336 } else {
337 if (arr[last] >> 32 ==
338 std::max(uint32_t(arr[i] >> 32),
339 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
340 vec.emplace_back(arr[i], ~(uint32_t)(arr[last] >> 32));
341 }
342 }
343 }
344};
345
350 uint32_t k, i = 0, last = 0;
351 std::vector<__uint128_t> arr;
352
353 Adaptive64(uint32_t k) : k(k), arr(k) {}
354 Adaptive64(const Adaptive64 &other) = default;
355 Adaptive64 &operator=(const Adaptive64 &other) = default;
356
357 void naive(uint32_t index, uint64_t hash) {
358 arr[i] = (__uint128_t)~hash << 32 | index;
359 if (++i == k)
360 i = 0;
361 }
362
363 void naive2(uint32_t index, uint64_t hash) {
364 // flip the hash bits so we can take the maximum
365 arr[i] = (__uint128_t)~hash << 32 | index;
366
367 if (arr[i] > arr[last]) {
368 last = i;
369 } else if (last == i) {
370 for (int j = k - 1; j >= 0; j--) {
371 if (arr[j] > arr[last]) {
372 last = j;
373 }
374 }
375 }
376
377 if (++i == k)
378 i = 0;
379 }
380
381 void insert(uint32_t index, uint64_t hash) {
382 if (k < 16) {
383 naive(index, hash);
384 } else {
385 return naive2(index, hash);
386 }
387 }
388
389 uint32_t min() {
390 if (k < 16) {
391 int i = k - 1;
392 for (int j = k - 2; j >= 0; j--) {
393 if (arr[j] > arr[i]) {
394 i = j;
395 }
396 }
397 return arr[i];
398 } else {
399 return arr[last];
400 }
401 }
402
403 uint64_t min_hash() {
404 if (k < 16) {
405 int i = k - 1;
406 for (int j = k - 2; j >= 0; j--) {
407 if (arr[j] > arr[i]) {
408 i = j;
409 }
410 }
411 return ~(uint64_t)(arr[i] >> 32);
412 } else {
413 return ~(uint64_t)(arr[last] >> 32);
414 }
415 }
416
417 void min_syncmer(std::vector<uint32_t> &vec) {
418 if (k < 16) {
419 unsigned int j = k - 1;
420 for (int l = k - 2; l >= 0; l--) {
421 if (arr[l] > arr[j]) {
422 j = l;
423 }
424 }
425 if (arr[j] >> 32 ==
426 std::max(uint32_t(arr[i] >> 32),
427 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
428 vec.emplace_back(arr[i]);
429 }
430 } else {
431 if (arr[last] >> 32 ==
432 std::max(uint32_t(arr[i] >> 32),
433 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
434 vec.emplace_back(arr[i]);
435 }
436 }
437 }
438
439 void min_syncmer(std::vector<std::pair<uint32_t, uint64_t>> &vec) {
440 if (k < 16) {
441 unsigned int j = k - 1;
442 for (int l = k - 2; l >= 0; l--) {
443 if (arr[l] > arr[j]) {
444 j = l;
445 }
446 }
447 if (arr[j] >> 32 ==
448 std::max(uint32_t(arr[i] >> 32),
449 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
450 vec.emplace_back(arr[i], ~(uint64_t)(arr[j] >> 32));
451 }
452 } else {
453 if (arr[last] >> 32 ==
454 std::max(uint32_t(arr[i] >> 32),
455 uint32_t(arr[i ? i - 1 : k - 1] >> 32))) {
456 vec.emplace_back(arr[i], ~(uint64_t)(arr[last] >> 32));
457 }
458 }
459 }
460};
461} // namespace digest::ds
462
463#endif // DATA_STRUCTURE_HPP
Definition data_structure.hpp:27
Same as Adaptive but uses 64-bit hashes.
Definition data_structure.hpp:349
Adaptive data structure. Selects between Naive and Naive2 based on the large window size.
Definition data_structure.hpp:233
Definition data_structure.hpp:33
virtual uint32_t min()
virtual void min_syncmer(std::vector< std::pair< uint32_t, T > > &vec)
virtual void min_syncmer(std::vector< uint32_t > &vec)
Naive2 data structure. Remembers the last minimum index and only loops through the array when this in...
Definition data_structure.hpp:181
Naive data structure. Naively loops through the array to find the minimum.
Definition data_structure.hpp:114
Segment Tree data structure. Supports log(n) point updates and range minimum queries.
Definition data_structure.hpp:64