-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sqrt decomposition; tree transfer; tree diameter;
- Loading branch information
old-yan
committed
Jun 23, 2024
1 parent
d1c41a8
commit b058269
Showing
30 changed files
with
1,156 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
*/ |
Oops, something went wrong.