Skip to content

Commit

Permalink
sqrt decomposition; tree transfer; tree diameter;
Browse files Browse the repository at this point in the history
  • Loading branch information
old-yan committed Jun 23, 2024
1 parent d1c41a8 commit b058269
Show file tree
Hide file tree
Showing 30 changed files with 1,156 additions and 41 deletions.
1 change: 1 addition & 0 deletions DS/GlobalHashMap.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
9. [J. Range Sets](https://qoj.ac/contest/1399/problem/7641)
10. [Associative Array](https://judge.yosupo.jp/problem/associative_array)(https://github.com/yosupo06/library-checker-problems/issues/376)
11. [Point Set Range Frequency](https://judge.yosupo.jp/problem/point_set_range_frequency)(https://github.com/yosupo06/library-checker-problems/issues/769)
12. [Number of Subsequences](https://judge.yosupo.jp/problem/number_of_subsequences)(https://github.com/yosupo06/library-checker-problems/issues/811)



Expand Down
2 changes: 2 additions & 0 deletions DS/LinkBucket.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
13. [#515. 【UR #19】前进四](https://uoj.ac/problem/515)
14. [Persistent Queue](https://judge.yosupo.jp/problem/persistent_queue)(https://github.com/yosupo06/library-checker-problems/issues/379)
15. [Persistent Unionfind](https://judge.yosupo.jp/problem/persistent_unionfind)(https://github.com/yosupo06/library-checker-problems/issues/405)
16. [Cycle Detection (Directed)](https://judge.yosupo.jp/problem/cycle_detection)(https://github.com/yosupo06/library-checker-problems/issues/534)
17. [Cycle Detection (Undirected)](https://judge.yosupo.jp/problem/cycle_detection_undirected)(https://github.com/yosupo06/library-checker-problems/issues/869)



Expand Down
117 changes: 117 additions & 0 deletions MATH/SqrtDecomposition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
最后修改:
20240621
测试环境:
gcc11.2,c++11
clang12.0,C++11
msvc14.2,C++14
*/
#ifndef __OY_SQRTDECOMPOSITION__
#define __OY_SQRTDECOMPOSITION__

#include <algorithm>
#include <cmath>
#include <cstdint>

namespace OY {
struct SqrtDecomposition {
struct iterator {
struct _range {
uint64_t m_quot, m_left, m_right;
template <typename Ostream>
friend Ostream &operator<<(Ostream &out, const _range &x) { return out << '(' << x.m_quot << ": " << x.m_left << '~' << x.m_right << ')'; }
} m_range;
uint64_t m_val;
iterator &operator--() {
if (m_range.m_quot == 1)
--m_range.m_quot;
else {
m_range.m_left = m_range.m_right + 1;
m_range.m_quot = m_val / m_range.m_left;
if (m_range.m_quot >= m_range.m_left)
m_range.m_right = m_range.m_left;
else
m_range.m_right = m_val / m_range.m_quot;
}
return *this;
}
iterator &operator++() {
if (m_range.m_quot + 1 < m_range.m_left) {
m_range.m_right = m_range.m_left - 1;
m_range.m_left = m_val / (m_range.m_quot + 2) + 1;
m_range.m_quot++;
} else if (--m_range.m_left)
m_range.m_quot = m_val / (m_range.m_right = m_range.m_left);
else
m_range.m_quot = -1;
return *this;
}
const _range &operator*() const { return m_range; }
const _range *operator->() const { return &m_range; }
bool operator!=(const iterator &rhs) const { return m_range.m_quot != rhs.m_range.m_quot; }
bool operator==(const iterator &rhs) const { return m_range.m_quot == rhs.m_range.m_quot; }
static iterator null(uint64_t val) { return {{uint64_t(-1)}, val}; }
};
struct reverse_iterator : iterator {
iterator base() const { return *this; }
reverse_iterator &operator--() {
iterator::operator++();
return *this;
}
reverse_iterator &operator++() {
iterator::operator--();
return *this;
}
static reverse_iterator null(uint64_t val) {
reverse_iterator res;
res.m_range = {0, val + 1, uint64_t(-1)}, res.m_val = val;
return res;
}
};
uint64_t m_val;
SqrtDecomposition(uint64_t val) : m_val(val) {}
uint64_t size() const {
uint64_t r = std::sqrt((long double)m_val);
return r * 2 - (m_val * 2 + 1 < (r + 1) * r * 2);
}
iterator lower_bound(uint64_t quot) const {
if (!quot) return rend().base();
if (quot > m_val) return end();
uint64_t right = m_val / quot;
if (quot < right) {
uint64_t left = m_val / (quot + 1) + 1;
return iterator{{quot, left, right}, m_val};
} else
return iterator{{m_val / right, right, right}, m_val};
}
iterator upper_bound(uint64_t quot) const { return lower_bound(quot + 1); }
iterator find_by_divisor(uint64_t divisor) const {
if (!divisor) return end();
if (divisor > m_val) return rend().base();
uint64_t quot = m_val / divisor;
if (divisor <= quot) return iterator{{quot, divisor, divisor}, m_val};
uint64_t right = m_val / quot;
uint64_t left = m_val / (quot + 1) + 1;
return iterator{{quot, left, right}, m_val};
}
iterator begin() const { return iterator{{1, m_val / 2 + 1, m_val}, m_val}; }
iterator end() const { return iterator::null(m_val); }
reverse_iterator rbegin() const {
reverse_iterator res;
res.m_range = {m_val, 1, 1}, res.m_val = m_val;
return res;
}
reverse_iterator rend() const { return reverse_iterator::null(m_val); }
};
template <typename Ostream>
Ostream &operator<<(Ostream &out, const SqrtDecomposition &x) {
out << '{';
for (auto i : x) {
if (i.m_quot != 1) out << ", ";
out << i;
}
return out << '}';
}
}

#endif
95 changes: 95 additions & 0 deletions MATH/SqrtDecomposition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
### 一、模板类别

​ 数学:数论分块。

练习题目:

1. [Enumerate Quotients](https://judge.yosupo.jp/problem/enumerate_quotients)(https://github.com/yosupo06/library-checker-problems/issues/922)



### 二、模板功能

​ 本模板提供一个 `SqrtDecomposition` 类,按照 `1~n` 每个数字作为除数去整除 `n` 的结果分为了若干个区间。

​ 本模板支持基于范围的 `for` 循环,也支持反向迭代循环;可以通过整除结果使用 `lower_bound``upper_bound` 获取迭代器。

### 三、模板示例

```c++
#include "IO/FastIO.h"
#include "MATH/SqrtDecomposition.h"

int main() {
uint32_t n = 105;
OY::SqrtDecomposition sd(n);
cout << "there are " << sd.size() << " blocks\n";
for (auto range : sd) {
cout << "floor(" << n << " / x) = " << range.m_quot << ", \t" << range.m_left << " <= x <= " << range.m_right << endl;
}

// 也可以反向迭代
cout << "\nreversed:\n";
for (auto it = sd.rbegin(); it != sd.rend(); ++it) {
cout << "floor(" << n << " / x) = " << it->m_quot << ", \t" << it->m_left << " <= x <= " << it->m_right << endl;
}

// 可以二分找到一个迭代器
cout << "\nlower_bound:\n";
auto it = sd.lower_bound(13);
cout << "floor(" << n << " / x) = " << it->m_quot << ", \t" << it->m_left << " <= x <= " << it->m_right << endl;
it = sd.upper_bound(13);
cout << "floor(" << n << " / x) = " << it->m_quot << ", \t" << it->m_left << " <= x <= " << it->m_right << endl;
}
```

```
#输出如下
there are 19 blocks
floor(105 / x) = 1, 53 <= x <= 105
floor(105 / x) = 2, 36 <= x <= 52
floor(105 / x) = 3, 27 <= x <= 35
floor(105 / x) = 4, 22 <= x <= 26
floor(105 / x) = 5, 18 <= x <= 21
floor(105 / x) = 6, 16 <= x <= 17
floor(105 / x) = 7, 14 <= x <= 15
floor(105 / x) = 8, 12 <= x <= 13
floor(105 / x) = 9, 11 <= x <= 11
floor(105 / x) = 10, 10 <= x <= 10
floor(105 / x) = 11, 9 <= x <= 9
floor(105 / x) = 13, 8 <= x <= 8
floor(105 / x) = 15, 7 <= x <= 7
floor(105 / x) = 17, 6 <= x <= 6
floor(105 / x) = 21, 5 <= x <= 5
floor(105 / x) = 26, 4 <= x <= 4
floor(105 / x) = 35, 3 <= x <= 3
floor(105 / x) = 52, 2 <= x <= 2
floor(105 / x) = 105, 1 <= x <= 1
reversed:
floor(105 / x) = 105, 1 <= x <= 1
floor(105 / x) = 52, 2 <= x <= 2
floor(105 / x) = 35, 3 <= x <= 3
floor(105 / x) = 26, 4 <= x <= 4
floor(105 / x) = 21, 5 <= x <= 5
floor(105 / x) = 17, 6 <= x <= 6
floor(105 / x) = 15, 7 <= x <= 7
floor(105 / x) = 13, 8 <= x <= 8
floor(105 / x) = 11, 9 <= x <= 9
floor(105 / x) = 10, 10 <= x <= 10
floor(105 / x) = 9, 11 <= x <= 11
floor(105 / x) = 8, 12 <= x <= 13
floor(105 / x) = 7, 14 <= x <= 15
floor(105 / x) = 6, 16 <= x <= 17
floor(105 / x) = 5, 18 <= x <= 21
floor(105 / x) = 4, 22 <= x <= 26
floor(105 / x) = 3, 27 <= x <= 35
floor(105 / x) = 2, 36 <= x <= 52
floor(105 / x) = 1, 53 <= x <= 105
lower_bound:
floor(105 / x) = 13, 8 <= x <= 8
floor(105 / x) = 15, 7 <= x <= 7
```

5 changes: 3 additions & 2 deletions STR/SuffixArray.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
7. [P3809 【模板】后缀排序](https://www.luogu.com.cn/problem/P3809)
8. [P4051 [JSOI2007] 字符加密](https://www.luogu.com.cn/problem/P4051)
9. [P4094 [HEOI2016/TJOI2016] 字符串](https://www.luogu.com.cn/problem/P4094)
10. [Number of Substrings](https://judge.yosupo.jp/problem/number_of_substrings)(https://github.com/yosupo06/library-checker-problems/issues/123)
11. [Suffix Array](https://judge.yosupo.jp/problem/suffixarray)(https://github.com/yosupo06/library-checker-problems/issues/50)
10. [Suffix Array](https://judge.yosupo.jp/problem/suffixarray)(https://github.com/yosupo06/library-checker-problems/issues/50)
11. [Number of Substrings](https://judge.yosupo.jp/problem/number_of_substrings)(https://github.com/yosupo06/library-checker-problems/issues/123)
12. [Longest Common Substring](https://judge.yosupo.jp/problem/longest_common_substring)(https://github.com/yosupo06/library-checker-problems/issues/889)

### 二、模板功能

Expand Down
46 changes: 15 additions & 31 deletions TEST/benchmark/rmq_table_random_range_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ CPU: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
在 atcoder C++ 23 (clang 16.0.6) 语言条件下测试
cmd: clang++ -std=c++2b -Wall -Wextra -O2 -DONLINE_JUDGE -DATCODER -mtune=native -march=native -fconstexpr-depth=2147483647 -fconstexpr-steps=2147483647 -I/opt/boost/clang/include -L/opt/boost/clang/lib -I/opt/ac-library -I/usr/include/eigen3 -fuse-ld=lld
CPU: Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz
在 luogu C++ 20 (gcc 13.2.0) 语言条件下测试
cmd: g++ -x c++ -std=C++2a -fPIC -DONLINE_JUDGE -Wall -fno-asm -lm -march=native
CPU: Intel(R) Xeon(R) Platinum 8369HC CPU @ 3.30GHz
*/
#include <cassert>
#include <chrono>
Expand Down Expand Up @@ -129,7 +125,7 @@ int main() {
RUN(Bench::RandomRange::run<0, OY::STMaxTable<uint32_t>, 1 << 15, N, Q>);
RUN(Bench::RandomRange::run<0, OY::CatMaxTable<uint32_t>, 1 << 15, N, Q>);
RUN(Bench::RandomRange::run<0, OY::ZKW::Tree<Node>, 1 << 10, N, Q>);
RUN(Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t, N * 2>, 1 << 9, N, Q>);
RUN(Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t>, 1 << 9, N, Q>);
RUN(Bench::RandomRange::run<0, OY::MaskRMQMaxValueTable<uint32_t>, 1 << 14, N, Q>);
using SqrtMaxTable_random = OY::SqrtMaxTable<uint32_t, OY::Sqrt::RandomController<>>;
RUN(Bench::RandomRange::run<0, SqrtMaxTable_random, 1 << 15, N, Q>);
Expand All @@ -139,36 +135,24 @@ int main() {
/*
atcoder g++
build time query time time for 1e10 query
50 100 % 70(33554432) 2086 100 % Bench::RandomRange::run<0, OY::STMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
60 120 % 59(33554432) 1758 84 % Bench::RandomRange::run<0, OY::CatMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
4 8 % 121(1048576) 115394 5532 % Bench::RandomRange::run<0, OY::ZKW::Tree<Node>, 1 << 10, N, Q> 4503539713631232
11 22 % 172(524288) 328063 15727 % Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t, N * 2>, 1 << 9, N, Q> 2251769856815616
15 30 % 175(16777216) 10430 500 % Bench::RandomRange::run<0, OY::MaskRMQMaxValueTable<uint32_t>, 1 << 14, N, Q> 72056635418099712
5 10 % 76(33554432) 2264 109 % Bench::RandomRange::run<0, SqrtMaxTable_random, 1 << 15, N, Q> 144113270836199424
6 12 % 88(33554432) 2622 126 % Bench::RandomRange::run<0, SqrtMaxTable_nonrandom, 1 << 15, N, Q> 144113270836199424
42 100 % 71(33554432) 2115 100 % Bench::RandomRange::run<0, OY::STMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
54 129 % 61(33554432) 1817 86 % Bench::RandomRange::run<0, OY::CatMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
4 10 % 115(1048576) 109672 5185 % Bench::RandomRange::run<0, OY::ZKW::Tree<Node>, 1 << 10, N, Q> 4503539713631232
25 60 % 152(524288) 289916 13708 % Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t>, 1 << 9, N, Q> 2251769856815616
11 26 % 169(16777216) 10073 476 % Bench::RandomRange::run<0, OY::MaskRMQMaxValueTable<uint32_t>, 1 << 14, N, Q> 72056635418099712
5 12 % 76(33554432) 2264 107 % Bench::RandomRange::run<0, SqrtMaxTable_random, 1 << 15, N, Q> 144113270836199424
6 14 % 88(33554432) 2622 124 % Bench::RandomRange::run<0, SqrtMaxTable_nonrandom, 1 << 15, N, Q> 144113270836199424
*/
/*
atcoder clang++
build time query time time for 1e10 query
38 100 % 62(33554432) 1847 100 % Bench::RandomRange::run<0, OY::STMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
50 132 % 67(33554432) 1996 108 % Bench::RandomRange::run<0, OY::CatMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
3 8 % 114(1048576) 108718 5886 % Bench::RandomRange::run<0, OY::ZKW::Tree<Node>, 1 << 10, N, Q> 4503539713631232
13 34 % 179(524288) 341415 18485 % Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t, N * 2>, 1 << 9, N, Q> 2251769856815616
15 39 % 179(16777216) 10669 578 % Bench::RandomRange::run<0, OY::MaskRMQMaxValueTable<uint32_t>, 1 << 14, N, Q> 72056635418099712
6 16 % 95(33554432) 2831 153 % Bench::RandomRange::run<0, SqrtMaxTable_random, 1 << 15, N, Q> 144113270836199424
5 13 % 115(33554432) 3427 186 % Bench::RandomRange::run<0, SqrtMaxTable_nonrandom, 1 << 15, N, Q> 144113270836199424
36 100 % 61(33554432) 1817 100 % Bench::RandomRange::run<0, OY::STMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
49 136 % 69(33554432) 2056 113 % Bench::RandomRange::run<0, OY::CatMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
3 8 % 105(1048576) 100135 5511 % Bench::RandomRange::run<0, OY::ZKW::Tree<Node>, 1 << 10, N, Q> 4503539713631232
25 69 % 171(524288) 326156 17950 % Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t>, 1 << 9, N, Q> 2251769856815616
11 31 % 178(16777216) 10609 584 % Bench::RandomRange::run<0, OY::MaskRMQMaxValueTable<uint32_t>, 1 << 14, N, Q> 72056635418099712
6 17 % 95(33554432) 2831 156 % Bench::RandomRange::run<0, SqrtMaxTable_random, 1 << 15, N, Q> 144113270836199424
5 14 % 114(33554432) 3397 187 % Bench::RandomRange::run<0, SqrtMaxTable_nonrandom, 1 << 15, N, Q> 144113270836199424
*/
/*
luogu g++
build time query time time for 1e10 query
44 100 % 66(33554432) 1966 100 % Bench::RandomRange::run<0, OY::STMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
55 125 % 60(33554432) 1788 91 % Bench::RandomRange::run<0, OY::CatMaxTable<uint32_t>, 1 << 15, N, Q> 144113270836199424
4 9 % 108(1048576) 102996 5239 % Bench::RandomRange::run<0, OY::ZKW::Tree<Node>, 1 << 10, N, Q> 4503539713631232
10 23 % 209(524288) 398635 20276 % Bench::RandomRange::run<0, OY::Seg::Tree<Node, OY::Seg::Ignore, true, uint32_t, N * 2>, 1 << 9, N, Q> 2251769856815616
14 32 % 141(16777216) 8404 427 % Bench::RandomRange::run<0, OY::MaskRMQMaxValueTable<uint32_t>, 1 << 14, N, Q> 72056635418099712
8 18 % 78(33554432) 2324 118 % Bench::RandomRange::run<0, SqrtMaxTable_random, 1 << 15, N, Q> 144113270836199424
8 18 % 92(33554432) 2741 139 % Bench::RandomRange::run<0, SqrtMaxTable_nonrandom, 1 << 15, N, Q> 144113270836199424
*/
73 changes: 73 additions & 0 deletions TEST/local/SqrtDecomposition_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include "IO/FastIO.h"
#include "MATH/SqrtDecomposition.h"

int main() {
uint32_t n = 105;
OY::SqrtDecomposition sd(n);
cout << "there are " << sd.size() << " blocks\n";
for (auto range : sd) {
cout << "floor(" << n << " / x) = " << range.m_quot << ", \t" << range.m_left << " <= x <= " << range.m_right << endl;
}

// 也可以反向迭代
cout << "\nreversed:\n";
for (auto it = sd.rbegin(); it != sd.rend(); ++it) {
cout << "floor(" << n << " / x) = " << it->m_quot << ", \t" << it->m_left << " <= x <= " << it->m_right << endl;
}

// 可以二分找到一个迭代器
cout << "\nlower_bound:\n";
auto it = sd.lower_bound(13);
cout << "floor(" << n << " / x) = " << it->m_quot << ", \t" << it->m_left << " <= x <= " << it->m_right << endl;
it = sd.upper_bound(13);
cout << "floor(" << n << " / x) = " << it->m_quot << ", \t" << it->m_left << " <= x <= " << it->m_right << endl;
}
/*
#输出如下
there are 19 blocks
floor(105 / x) = 1, 53 <= x <= 105
floor(105 / x) = 2, 36 <= x <= 52
floor(105 / x) = 3, 27 <= x <= 35
floor(105 / x) = 4, 22 <= x <= 26
floor(105 / x) = 5, 18 <= x <= 21
floor(105 / x) = 6, 16 <= x <= 17
floor(105 / x) = 7, 14 <= x <= 15
floor(105 / x) = 8, 12 <= x <= 13
floor(105 / x) = 9, 11 <= x <= 11
floor(105 / x) = 10, 10 <= x <= 10
floor(105 / x) = 11, 9 <= x <= 9
floor(105 / x) = 13, 8 <= x <= 8
floor(105 / x) = 15, 7 <= x <= 7
floor(105 / x) = 17, 6 <= x <= 6
floor(105 / x) = 21, 5 <= x <= 5
floor(105 / x) = 26, 4 <= x <= 4
floor(105 / x) = 35, 3 <= x <= 3
floor(105 / x) = 52, 2 <= x <= 2
floor(105 / x) = 105, 1 <= x <= 1
reversed:
floor(105 / x) = 105, 1 <= x <= 1
floor(105 / x) = 52, 2 <= x <= 2
floor(105 / x) = 35, 3 <= x <= 3
floor(105 / x) = 26, 4 <= x <= 4
floor(105 / x) = 21, 5 <= x <= 5
floor(105 / x) = 17, 6 <= x <= 6
floor(105 / x) = 15, 7 <= x <= 7
floor(105 / x) = 13, 8 <= x <= 8
floor(105 / x) = 11, 9 <= x <= 9
floor(105 / x) = 10, 10 <= x <= 10
floor(105 / x) = 9, 11 <= x <= 11
floor(105 / x) = 8, 12 <= x <= 13
floor(105 / x) = 7, 14 <= x <= 15
floor(105 / x) = 6, 16 <= x <= 17
floor(105 / x) = 5, 18 <= x <= 21
floor(105 / x) = 4, 22 <= x <= 26
floor(105 / x) = 3, 27 <= x <= 35
floor(105 / x) = 2, 36 <= x <= 52
floor(105 / x) = 1, 53 <= x <= 105
lower_bound:
floor(105 / x) = 13, 8 <= x <= 8
floor(105 / x) = 15, 7 <= x <= 7
*/
Loading

0 comments on commit b058269

Please sign in to comment.