Skip to content

Commit

Permalink
add tree doc files;
Browse files Browse the repository at this point in the history
  • Loading branch information
old-yan committed Sep 22, 2023
1 parent 673231d commit 649903e
Show file tree
Hide file tree
Showing 56 changed files with 3,474 additions and 293 deletions.
14 changes: 7 additions & 7 deletions DS/AdjDiff.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

1. 数据类型

类型设定 `size_type = uint32_t`表示矩阵大小的类型
类型设定 `size_type = uint32_t`表示数组大小、编号的类型

模板参数 `typename Tp` ,表示元素类型。

Expand Down Expand Up @@ -46,7 +46,7 @@

构造参数中的 `mapping` 参数,入参为下标,返回值须为一个 `Tp` 对象。默认情况下, `mapping``AdjDiff::NoInit` 类,表示不进行初始化,比如要建立一颗空的差分表,由于全局变量值本身就是零,所以无需进行初始化,此时的初状态为 `TABLE_ANY` 态,可以认为为任意状态。如果进行了有意义的初始化,则初状态为 `TABLE_VALUE` 态。

#### 2.重置
#### 2.重置(resize)

1. 数据类型

Expand Down Expand Up @@ -82,7 +82,7 @@

本操作须在值态下进行。

本函数没有进行参数检查,所以请自己确保下标合法。(行号、列号位于 `[0,n)`
本函数没有进行参数检查,所以请自己确保下标合法。(行号位于 `[0,n)`

#### 4.单点赋值(modify)

Expand All @@ -100,7 +100,7 @@

本操作须在值态下进行。

本函数没有进行参数检查,所以请自己确保下标合法。(行号、列号位于 `[0,n)`
本函数没有进行参数检查,所以请自己确保下标合法。(行号位于 `[0,n)`

#### 5.区间增值(add)

Expand All @@ -120,7 +120,7 @@

本操作须在差分态下进行。

本函数没有进行参数检查,所以请自己确保下标合法。(行号、列号位于 `[0,n)`
本函数没有进行参数检查,所以请自己确保下标合法。(行号位于 `[0,n)`

#### 6.单点查询(query)

Expand All @@ -136,7 +136,7 @@

本操作须在值态下进行。

本函数没有进行参数检查,所以请自己确保下标合法。(行号、列号位于 `[0,n)`
本函数没有进行参数检查,所以请自己确保下标合法。(行号位于 `[0,n)`

#### 7.区间查询(query)

Expand All @@ -154,7 +154,7 @@

本操作须在前缀和态下进行。

本函数没有进行参数检查,所以请自己确保下标合法。(行号、列号位于 `[0,n)`
本函数没有进行参数检查,所以请自己确保下标合法。(行号位于 `[0,n)`

#### 8.查询全部(query_all)

Expand Down
2 changes: 1 addition & 1 deletion DS/AdjDiff2D.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@

构造参数中的 `mapping` 参数,入参为行下标、列下标,返回值须为一个 `Tp` 对象。默认情况下, `mapping``AdjDiff2D::NoInit` 类,表示不进行初始化,比如要建立一颗空的差分表,由于全局变量值本身就是零,所以无需进行初始化,此时的初状态为 `TABLE_ANY` 态,可以认为为任意状态。如果进行了有意义的初始化,则初状态为 `TABLE_VALUE` 态。

#### 2.重置
#### 2.重置(resize)

1. 数据类型

Expand Down
6 changes: 3 additions & 3 deletions DS/Cartesiantree.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
最后修改:
20230827
20230922
测试环境:
gcc11.2,c++11
clang12.0,C++11
Expand Down Expand Up @@ -29,7 +29,7 @@ namespace OY {
template <typename Tp, size_type MAX_NODE>
typename SolverHelper<Tp, MAX_NODE>::node SolverHelper<Tp, MAX_NODE>::s_stack[MAX_NODE];
template <typename Tp, size_type MAX_NODE = 1 << 20, typename InitMapping, typename LchildCallback, typename RchildCallback, typename Compare = std::less<Tp>>
size_type solve(size_type length, InitMapping mapping, LchildCallback lchild_call, RchildCallback rchild_call, Compare comp = Compare(), const Tp &max = std::numeric_limits<Tp>::max()) {
size_type solve(size_type length, InitMapping mapping, LchildCallback &&lchild_call, RchildCallback &&rchild_call, Compare comp = Compare(), const Tp &max = std::numeric_limits<Tp>::max()) {
SolverHelper<Tp, MAX_NODE>::s_stack[0].m_index = -1;
SolverHelper<Tp, MAX_NODE>::s_stack[0].m_value = max;
size_type len = 1;
Expand All @@ -54,7 +54,7 @@ namespace OY {
return SolverHelper<Tp, MAX_NODE>::s_stack[0].m_rchild;
}
template <size_type MAX_NODE = 1 << 20, typename Iterator, typename LchildCallback, typename RchildCallback, typename Tp = typename std::iterator_traits<Iterator>::value_type, typename Compare = std::less<Tp>>
size_type solve(Iterator first, Iterator last, LchildCallback lchild_call, RchildCallback rchild_call, Compare comp = Compare(), const Tp &max = std::numeric_limits<Tp>::max()) {
size_type solve(Iterator first, Iterator last, LchildCallback &&lchild_call, RchildCallback &&rchild_call, Compare comp = Compare(), const Tp &max = std::numeric_limits<Tp>::max()) {
return solve<Tp, MAX_NODE>(
last - first, [&](size_type i) { return *(first + i); }, lchild_call, rchild_call, comp, max);
}
Expand Down
4 changes: 2 additions & 2 deletions DS/Cartesiantree.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@

输入参数 `InitMapping mapping` ,表示从下标到数组的值的映射函数。

输入参数 `LchildCallback lchild_call` ,表示当找到一个元素的左孩子时的回调函数。
输入参数 `LchildCallback &&lchild_call` ,表示当找到一个元素的左孩子时的回调函数。

输入参数 `RchildCallback rchild_call` ,表示当找到一个元素的右孩子时的回调函数。
输入参数 `RchildCallback &&rchild_call` ,表示当找到一个元素的右孩子时的回调函数。

输入参数 `Compare comp` ,表示数组元素间的比较函数。

Expand Down
27 changes: 18 additions & 9 deletions DS/MaskRMQ.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,35 @@ namespace OY {
template <typename InitMapping = NoInit>
void resize(size_type length, InitMapping mapping = InitMapping()) {
if (!(m_size = length)) return;
size_type capacity = (m_size + block_size - 1) / block_size * block_size;
m_raw = s_buffer + s_use_count, m_mask = s_mask_buffer + s_use_count;
s_use_count += capacity;
s_use_count += m_size;
if constexpr (!std::is_same<InitMapping, NoInit>::value) {
for (size_type i = 0; i < m_size; i++) m_raw[i].set(mapping(i));
for (size_type i = m_size; i < capacity; i++) m_raw[i].set(m_raw[m_size - 1].get());
size_type stack[block_size];
for (size_type i = 0; i < capacity; i += block_size) {
for (size_type i = 0; i != m_size; i++) m_raw[i].set(mapping(i));
size_type stack[block_size], i;
for (i = 0; i + block_size <= m_size; i += block_size) {
node *cur_raw = m_raw + i;
MaskType *cur_mask = m_mask + i, mask = 0;
size_type len = 0;
for (size_type j = 0; j < block_size; j++) {
for (size_type j = 0; j != block_size; j++) {
while (len && node::comp(cur_raw[stack[len - 1]].get(), cur_raw[j].get())) mask &= ~(MaskType(1) << stack[--len]);
stack[len++] = j, mask |= MaskType(1) << j;
cur_mask[j] = mask;
}
}
m_inter_table.resize(capacity / block_size, [&](size_type i) { return m_raw - s_buffer + i * block_size + _inner_query(m_mask[(i + 1) * block_size - 1]); });
if (i != m_size) {
node *cur_raw = m_raw + i;
MaskType *cur_mask = m_mask + i, mask = 0;
size_type len = 0;
for (size_type j = 0, rem = m_size - i; j != rem; j++) {
while (len && node::comp(cur_raw[stack[len - 1]].get(), cur_raw[j].get())) mask &= ~(MaskType(1) << stack[--len]);
stack[len++] = j, mask |= MaskType(1) << j;
cur_mask[j] = mask;
}
}
size_type tot = (m_size + block_size - 1) / block_size;
m_inter_table.resize(tot, [&](size_type i) { return m_raw - s_buffer + i * block_size + _inner_query(m_mask[std::min((i + 1) * block_size, m_size) - 1]); });
} else
m_inter_table.resize(capacity / block_size, [&](size_type i) { return i * block_size; });
m_inter_table.resize((m_size + block_size - 1) / block_size, [&](size_type i) { return i * block_size; });
}
template <typename Iterator>
void reset(Iterator first, Iterator last) {
Expand Down
98 changes: 98 additions & 0 deletions TEST/local/AdjDiffTree_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "IO/FastIO.h"
#include "TREE/AdjDiffTree.h"
#include "TREE/FlatTree.h"

// 手动模式
void Ad_manual() {
// 树可以是 FlatTree LinkTree 或者 VectorTree 均可
// 一个无权树
OY::FlatTree::Tree<bool, 100000> T(6);
// 加边
T.add_edge(0, 1);
T.add_edge(0, 2);
T.add_edge(0, 3);
T.add_edge(3, 4);
T.add_edge(3, 5);
// 预备
T.prepare();
T.set_root(0);
cout << T << endl;

// 假定每个点的初值都是编号 * 100000
OY::AdjDiffTree::Table<int, decltype(T), false, 100000> Ad(&T, [&](int i) {
return i * 100000;
});
cout << Ad << endl;

// 子树增值
Ad.switch_to_difference_downward();
Ad.add_subtree(3, 1);
Ad.switch_to_value();
cout << Ad << endl;

// 路径增值
Ad.switch_to_difference_upward();
Ad.add_path(1, 4, 0, -1, 10);
Ad.switch_to_value();
cout << Ad << endl;

// 查询子树和
Ad.switch_to_presum_upward();
cout << "sum of subtree(3) = " << Ad.query_subtree(3) << endl;

// 查询路径和
Ad.switch_to_presum_downward();
cout << "sum of path(1~4) = " << Ad.query_path(1, 4, 0, -1) << endl;
}

// 自动模式
void Ad_auto() {
OY::FlatTree::Tree<bool, 100000> T(6);
T.add_edge(0, 1);
T.add_edge(0, 2);
T.add_edge(0, 3);
T.add_edge(3, 4);
T.add_edge(3, 5);
T.prepare();
T.set_root(0);
cout << T << endl;

OY::AdjDiffTree::Table<int, decltype(T), true, 100000> Ad(&T, [&](int i) {
return i * 100000;
});
cout << Ad << endl;

// 子树增值
Ad.add_subtree(3, 1);
cout << Ad << endl;

// 路径增值
Ad.add_path(1, 4, 0, -1, 10);
cout << Ad << endl;

// 查询子树和
cout << "sum of subtree(3) = " << Ad.query_subtree(3) << endl;

// 查询路径和
cout << "sum of path(1~4) = " << Ad.query_path(1, 4, 0, -1) << endl;
}

int main() {
Ad_manual();
Ad_auto();
}
/*
#输出如下
[0[1][2][3[4][5]]]
[0[100000][200000][300000[400000][500000]]]
[0[100000][200000][300001[400001][500001]]]
[10[100010][200000][300011[400011][500001]]]
sum of subtree(3) = 1200023
sum of path(1~4) = 800042
[0[1][2][3[4][5]]]
[0[100000][200000][300000[400000][500000]]]
[0[100000][200000][300001[400001][500001]]]
[10[100010][200000][300011[400011][500001]]]
sum of subtree(3) = 1200023
sum of path(1~4) = 800042
*/
133 changes: 133 additions & 0 deletions TEST/local/Centroid_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#include "IO/FastIO.h"
#include "TREE/Centroid.h"
#include "TREE/FlatTree.h"

void test_centroid() {
OY::FlatTree::Tree<bool, 100000> T(10);
T.add_edge(0, 1);
T.add_edge(1, 2);
T.add_edge(2, 3);
T.add_edge(3, 4);
T.add_edge(4, 5);
T.add_edge(5, 6);
T.add_edge(6, 7);
T.add_edge(7, 8);
T.add_edge(8, 9);
T.prepare();
T.set_root(0);
cout << T << endl;

// 找重心
auto centroid = OY::Centroid::Centroid<decltype(T), 100000>(&T).centroid();
cout << "first centroid = " << centroid.first << endl;
cout << "second centroid = " << centroid.second << endl;

T.resize(9);
T.add_edge(0, 1);
T.add_edge(1, 2);
T.add_edge(2, 3);
T.add_edge(3, 4);
T.add_edge(4, 5);
T.add_edge(5, 6);
T.add_edge(6, 7);
T.add_edge(7, 8);
T.prepare();
T.set_root(0);
cout << T << endl;

// 找重心
centroid = OY::Centroid::Centroid<decltype(T), 100000>(&T).centroid();
cout << "first centroid = " << centroid.first << endl;
// 此时只有一个重心
cout << "second centroid = " << int(centroid.second) << endl;
}

void test_tree_trie() {
OY::FlatTree::Tree<bool, 100000> T(4);
T.add_edge(0, 1);
T.add_edge(0, 2);
T.add_edge(0, 3);
T.prepare();
cout << T << endl;

// 以 0 为根时,给树中每个结点为根的子树的形态编号
auto ids = OY::Centroid::TreeTrie::get(T, 0);
// 显然,叶子结点形态均相同,根结点独占一种形态
for (int i = 0; i < 4; i++) cout << "shape of " << i << " = " << ids[i] << endl;

// 再建一棵树,把前面那棵树的形态给包含进去
T.resize(9);
T.add_edge(8, 0);
T.add_edge(0, 1);
T.add_edge(0, 2);
T.add_edge(8, 3);
T.add_edge(8, 4);
T.add_edge(4, 5);
T.add_edge(4, 6);
T.add_edge(4, 7);
T.prepare();
cout << T << endl;

// 以 8 为根时,给树中每个结点为根的子树的形态编号
ids = OY::Centroid::TreeTrie::get(T, 8);
// 我们发现,以 4 为根的子树,和前面那棵树形态完全一致
for (int i = 0; i < 9; i++) cout << "shape of " << i << " = " << ids[i] << endl;
}

void test_centroid_decomposition() {
// 重心分治/点分树,主要用法技巧在 oj 测试中体现,此处只建出点分树
OY::FlatTree::Tree<bool, 100000> T(10);
T.add_edge(0, 1);
T.add_edge(1, 2);
T.add_edge(2, 3);
T.add_edge(3, 4);
T.add_edge(4, 5);
T.add_edge(5, 6);
T.add_edge(6, 7);
T.add_edge(7, 8);
T.add_edge(8, 9);
T.prepare();
cout << T << endl;

OY::FlatTree::Tree<bool, 100000> res(10);
auto total_root = OY::Centroid::CentroidDecomposition<100000>::solve(T, {}, [&](int sub_centroid, int cur_centroid) {
res.add_edge(sub_centroid, cur_centroid);
},
{});
res.prepare(), res.set_root(total_root);
// 显然,点分树比其原树,非常均衡
cout << res << endl;
}

int main() {
test_centroid();
test_tree_trie();
test_centroid_decomposition();
}
/*
#输出如下
[0[1[2[3[4[5[6[7[8[9]]]]]]]]]]
first centroid = 4
second centroid = 5
[0[1[2[3[4[5[6[7[8]]]]]]]]]
first centroid = 4
second centroid = -1
[0[1][2][3]]
shape of 0 = 1
shape of 1 = 0
shape of 2 = 0
shape of 3 = 0
[0[8[3][4[5][6][7]]][1][2]]
shape of 0 = 2
shape of 1 = 0
shape of 2 = 0
shape of 3 = 0
shape of 4 = 1
shape of 5 = 0
shape of 6 = 0
shape of 7 = 0
shape of 8 = 3
[0[1[2[3[4[5[6[7[8[9]]]]]]]]]]
[4[2[1[0]][3]][7[6[5]][8[9]]]]
*/
Loading

0 comments on commit 649903e

Please sign in to comment.