Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Competitive Programming C Plus Plus Library

A C++ library for competitive programming that includes a wide range of algorithms and data structures. Additionally, the project provides tests to ensure the correctness of its implementations.

14 changes: 9 additions & 5 deletions competitive_programming/scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ set -e

BUILD_DIR=build

echo "==> Compilando"
cmake --build $BUILD_DIR

echo "==> Rodando testes"
ctest --test-dir $BUILD_DIR
if [ -d $BUILD_DIR ]; then
echo "==> Compilando"
cmake --build $BUILD_DIR

echo "==> Rodando testes"
ctest --test-dir $BUILD_DIR
else
echo "o diretório $BUILD_DIR não existe"
fi
7 changes: 6 additions & 1 deletion competitive_programming/src/data_structures/disjoint_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <numeric>
#include <utility>

namespace data_structures
{

class DisjointSet
{
public:
Expand Down Expand Up @@ -82,4 +85,6 @@ class DisjointSet

/* the size of each disjoint set */
std::vector<unsigned> _size;
};
};

}
8 changes: 6 additions & 2 deletions competitive_programming/src/data_structures/fenwick_tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
#include <utility>
#include <type_traits>

namespace data_structures
{
template <typename T, typename Op>
requires std::regular_invocable<Op, T, T> && std::same_as<std::invoke_result_t<Op, T, T>, T>
requires std::regular_invocable<Op, T, T> && std::convertible_to<std::invoke_result_t<Op&, const T&, const T&>, T>
class FenwickTree
{
public:
Expand All @@ -23,7 +25,7 @@ class FenwickTree
* @param op the binary operator that calculates the result
* @param initial the default value that will be used when there is not value
*/
FenwickTree(std::size_t n, Op&& op, T initial):
FenwickTree(std::size_t n, const Op& op, T initial):
_ft(n + 1, initial),
_op(op),
_initial(initial)
Expand Down Expand Up @@ -81,4 +83,6 @@ template<typename T, typename Op>
auto make_fenwick_tree(std::size_t n, Op&& op, T initial)
{
return FenwickTree<T, std::decay_t<Op>>(n, std::forward<Op>(op), initial);
}

}
7 changes: 6 additions & 1 deletion competitive_programming/src/data_structures/segment_tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <algorithm>
#include <vector>

namespace data_structures
{

/**
* @brief Segtree traits concepts with method neutral that returns the neutral
* element and merge that returns the result of merging the results of children node
Expand Down Expand Up @@ -119,4 +122,6 @@ class SegTree

/** The container of nodes */
std::vector<value_type> _container;
};
};

}
15 changes: 11 additions & 4 deletions competitive_programming/src/data_structures/sparse_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@
#include <iterator>
#include <type_traits>

namespace data_structures
{

template <typename T, typename F>
requires std::regular_invocable<F, T, T> && std::same_as<std::invoke_result_t<F, T, T>, T>
requires std::regular_invocable<F&, const T&, const T&>
&& std::convertible_to<std::invoke_result_t<F&, const T&, const T&>, T>
&& std::copy_constructible<T>
class SparseTable
{
public:
Expand All @@ -25,8 +30,8 @@ class SparseTable
* @param op the binary function that calculates the answer
*/
template <typename It>
requires std::same_as<typename std::iterator_traits<It>::value_type, T>
SparseTable(It begin, It end, F&& op):
requires std::convertible_to<typename std::iterator_traits<It>::value_type, T>
SparseTable(It begin, It end, const F& op):
_op(op)
{
std::size_t n = std::distance(begin, end);
Expand Down Expand Up @@ -103,8 +108,10 @@ class SparseTable
* @param op the binary function that calculates the answer
*/
template<typename It, typename F>
auto make_sparse_table(It begin, It end, F&& op)
inline auto make_sparse_table(It begin, It end, F&& op)
{
using T = typename std::iterator_traits<It>::value_type;
return SparseTable<T, std::decay_t<F>>(begin, end, std::forward<F>(op));
}

}
2 changes: 1 addition & 1 deletion competitive_programming/src/math/mint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class mint

constexpr bool operator!=(const mint& rhs) const noexcept
{
return !(val == rhs.val);
return !(*this == rhs);
}

template<int m2>
Expand Down
44 changes: 43 additions & 1 deletion competitive_programming/src/math/pollard_rho.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,44 @@
#include <utility>
#include <chrono>
#include <numeric>
#include <algorithm>
#include <type_traits>

namespace math::factorization
{

/**
* @brief Compute the greatest common divisor of two numbers
* @param a a number
* @param b a number
* @return the greatest common divisor of a and b
* @note This function is necessary because std::gcd does not support __int128
* numbers, which are used in the factorization process.
*/
__int128 gcd(__int128 a, __int128 b)
{
while (b != 0)
{
auto temp = b;
b = a % b;
a = temp;
}

return a;
}

/**
* @brief Compute the absolute value of a number
* @param x a number
* @return the absolute value of x
* @note This function is necessary because std::abs does not support __int128
* numbers, which are used in the factorization process.
*/
constexpr __int128 abs(__int128 x)
{
return x < 0 ? -x : x;
}

/**
* @brief Take the modulo of the mutiplication of two numbers
* @param a a number
Expand Down Expand Up @@ -115,7 +149,15 @@ inline T rho(T n)
{
x = f(x, c, n);
y = f(f(y, c, n), c, n);
g = gcd(abs(x - y), n);

if constexpr(std::is_same_v<decltype(n), __int128>)
{
g = gcd(abs(x - y), n);
}
else
{
g = std::gcd(std::abs(x - y), n);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions competitive_programming/src/string/kmp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ namespace strings {
inline std::vector<int> kmp(const std::string& s)
{
int n = s.size();

if(n == 0)
return {};

std::vector<int> p(n);
p[0] = 0;
for(int i = 1; i < n; ++i) {
Expand Down
26 changes: 26 additions & 0 deletions competitive_programming/test/data_structures/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Disjoint Set
add_executable(disjoint-set disjoint_set.cpp)
target_include_directories(disjoint-set PRIVATE ${PROJECT_INCLUDE_DIR})
target_link_libraries(disjoint-set PRIVATE GTest::gtest GTest::gtest_main)

# Sparse Table
add_executable(sparse-table sparse_table.cpp)
target_include_directories(sparse-table PRIVATE ${PROJECT_INCLUDE_DIR})
target_link_libraries(sparse-table PRIVATE GTest::gtest GTest::gtest_main)

# Fenwick Tree
add_executable(fenwick-tree fenwick_tree.cpp)
target_include_directories(fenwick-tree PRIVATE ${PROJECT_INCLUDE_DIR})
target_link_libraries(fenwick-tree PRIVATE GTest::gtest GTest::gtest_main)

# Segment Tree
add_executable(segment-tree segment_tree.cpp)
target_include_directories(segment-tree PRIVATE ${PROJECT_INCLUDE_DIR})
target_link_libraries(segment-tree PRIVATE GTest::gtest GTest::gtest_main)

include(GoogleTest)

gtest_discover_tests(disjoint-set)
gtest_discover_tests(sparse-table)
gtest_discover_tests(fenwick-tree)
gtest_discover_tests(segment-tree)
82 changes: 82 additions & 0 deletions competitive_programming/test/data_structures/disjoint_set.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <gtest/gtest.h>

#include "data_structures/disjoint_set.hpp"

TEST(DisjointSet, DisconnectedGraphTest)
{
constexpr std::size_t N = 10;

data_structures::DisjointSet uf(N);

for(std::size_t u = 1; u < N; ++u)
for(std::size_t v = 0; v < u; ++v)
EXPECT_FALSE(uf.is_same(u, v));

for(std::size_t u = 0; u < N; ++u)
{
EXPECT_EQ(uf.findSet(u), u);
EXPECT_EQ(uf.getSize(u), 1u);
}
}

TEST(DisjointSet, PathTest)
{
constexpr std::size_t N = 10;

data_structures::DisjointSet uf(N);

for(std::size_t u = 1; u < N; ++u)
uf.unite(0, u);

const auto root = uf.findSet(0);

for(std::size_t u = 0; u < N; ++u)
{
EXPECT_EQ(uf.findSet(u), root);
EXPECT_EQ(uf.getSize(u), N);
}
}

TEST(DisjointSet, CompleteGraphTest)
{
constexpr std::size_t N = 10;

data_structures::DisjointSet uf(N);

for(std::size_t u = 1; u < N; ++u)
for(std::size_t v = 0; v < u; ++v)
uf.unite(u, v);

for(std::size_t u = 1; u < N; ++u)
for(std::size_t v = 0; v < u; ++v)
EXPECT_TRUE(uf.is_same(u, v));

const auto root = uf.findSet(0);

for(std::size_t u = 0; u < N; ++u)
{
EXPECT_EQ(uf.findSet(u), root);
EXPECT_EQ(uf.getSize(u), N);
}
}

TEST(DisjointSet, SplittedPathsTest)
{
constexpr std::size_t N = 10;

data_structures::DisjointSet uf(N);

for(std::size_t u = 2; u < N; ++u)
uf.unite(u % 2, u);

const std::size_t root[] = {uf.findSet(0), uf.findSet(1)};

EXPECT_NE(root[0], root[1]);

for(std::size_t u = 0; u < N; ++u)
{
EXPECT_EQ(uf.findSet(u), root[u % 2]);
EXPECT_EQ(uf.getSize(u), N / 2);
}
}

42 changes: 42 additions & 0 deletions competitive_programming/test/data_structures/fenwick_tree.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <gtest/gtest.h>

#include "data_structures/fenwick_tree.hpp"
#include <algorithm>
#include <numeric>
#include <utility>
#include <limits>

TEST(FenwickTree, SumTest)
{
constexpr std::size_t N = 10;

auto ft = data_structures::make_fenwick_tree<int>(N, std::plus<int>(), 0);

for(std::size_t i = 1; i <= N; ++i)
ft.update(i, i);

for(std::size_t i = 1; i <= N; ++i)
{
EXPECT_EQ(ft.query(i), i * (i + 1) / 2);

for(std::size_t j = 1; j < i; ++j)
EXPECT_EQ(ft.query(i) - ft.query(j - 1), (i + j) * (i - j + 1) / 2);
}
}

TEST(FenwickTree, MaxPrefixTest)
{
constexpr std::size_t N = 10;

const auto max = [](const auto& lhs, const auto& rhs) {
return std::max(lhs, rhs);
};

auto ft = data_structures::make_fenwick_tree<int>(N, max, std::numeric_limits<int>::min());

for(std::size_t i = 1; i <= N; ++i)
ft.update(i, i);

for(std::size_t i = 1; i <= N; ++i)
EXPECT_EQ(ft.query(i), static_cast<int>(i));
}
Loading
Loading