├── cheat_sheet.pdf ├── test ├── miscellaneous │ ├── fastio_test.cpp │ ├── pragma_test.cpp │ ├── change_stl_test.cpp │ ├── random_function_test.cpp │ ├── automaton_test.cpp │ ├── parallel_binary_search_test.cpp │ ├── sprague_grundy_test.cpp │ ├── identify_pattern_test.cpp │ ├── histogram_test.cpp │ ├── polyominoes_test.cpp │ ├── lis_test.cpp │ ├── counting_inversions_test.cpp │ ├── mo_algorithm_test.cpp │ ├── mo_with_update_test.cpp │ ├── scheduling_jobs_test.cpp │ └── kadane_test.cpp ├── data_structures │ ├── custom_hash_test.cpp │ ├── multiset_test.cpp │ ├── xor_trie_test.cpp │ ├── union_find_persistent_test.cpp │ ├── query_tree_test.cpp │ ├── union_find_with_rollback_test.cpp │ ├── dynamic_median_test.cpp │ ├── bit2d_test.cpp │ ├── bit2d_sparse_test.cpp │ ├── bit_range_test.cpp │ ├── union_find_test.cpp │ ├── lichao_tree_test.cpp │ ├── randomized_heap_test.cpp │ ├── line_container_test.cpp │ ├── permutation_test.cpp │ ├── bit_test.cpp │ ├── rmq_test.cpp │ ├── distinct_values_in_range_test.cpp │ ├── stack_query_test.cpp │ ├── queue_query_test.cpp │ ├── sparse_table_test.cpp │ ├── segment_tree_2d_test.cpp │ ├── merge_sort_tree_test.cpp │ ├── range_color_test.cpp │ ├── policy_based_tree_test.cpp │ ├── segment_tree_test.cpp │ ├── sqrt_decomposition_test.cpp │ ├── sqrt_tree_test.cpp │ ├── segment_tree_persistent_test.cpp │ ├── segment_tree_lazy_test.cpp │ ├── wavelet_tree_test.cpp │ ├── treap_test.cpp │ ├── segment_tree_iterative_test.cpp │ └── implicit_treap_test.cpp ├── graph │ ├── lca_test.cpp │ ├── lct_edge_test.cpp │ ├── checking_bipartiteness_online_test.cpp │ ├── floyd_warshall_test.cpp │ ├── prufer_code_test.cpp │ ├── edmond_blossoms_test.cpp │ ├── find_cycle_negative_test.cpp │ ├── kuhn_test.cpp │ ├── graph_theorem_test.cpp │ ├── centroid_decomposition_test.cpp │ ├── eulerian_path_test.cpp │ ├── flow_with_demand_test.cpp │ ├── dinic_test.cpp │ ├── 2_sat_test.cpp │ ├── hungarian_test.cpp │ ├── prim_test.cpp │ ├── kruskal_test.cpp │ ├── centroid_test.cpp │ ├── minimum_cost_maximum_flow_test.cpp │ ├── lct_vertex_test.cpp │ ├── dijkstra_test.cpp │ ├── mincut_test.cpp │ ├── vertex_cover_in_tree_test.cpp │ ├── tree_test.cpp │ ├── topological_sort_test.cpp │ ├── articulation_point_test.cpp │ ├── arborescence_test.cpp │ ├── bfs01_test.cpp │ ├── bridge_test.cpp │ ├── strongly_connected_component_test.cpp │ ├── lct_test.cpp │ └── tree_id_test.cpp ├── math │ ├── gauss_test.cpp │ ├── determinant_test.cpp │ ├── gauss_xor_test.cpp │ ├── rank_matrix_test.cpp │ ├── fft_test.cpp │ ├── lagrange_test.cpp │ ├── ntt_test.cpp │ ├── lagrange_poly_test.cpp │ ├── function_root_using_newton_test.cpp │ ├── modular_test.cpp │ ├── modular_int_test.cpp │ ├── montgomery_test.cpp │ ├── catalan_test.cpp │ ├── simpson_integration_test.cpp │ ├── extended_euclidean_test.cpp │ ├── gray_code_test.cpp │ ├── sieve_and_primes_test.cpp │ ├── division_trick_test.cpp │ ├── eulers_totient_test.cpp │ ├── chinese_remainder_theorem_test.cpp │ ├── floyd_cycle_finding_test.cpp │ ├── linear_sequence_with_berlekamp_massey_test.cpp │ ├── linear_sequence_with_reeds_sloane_test.cpp │ ├── karatsuba_test.cpp │ ├── prime_test.cpp │ ├── basic_math_test.cpp │ ├── matrix_test.cpp │ ├── fraction_test.cpp │ ├── bigint_test.cpp │ ├── xor_and_or_convolution_test.cpp │ └── binomial_coefficients_test.cpp ├── geometry │ ├── point3d_test.cpp │ ├── triangle_test.cpp │ ├── circle_area_union_test.cpp │ ├── count_lattices_test.cpp │ ├── convex_hull_trick_test.cpp │ ├── nearest_pair_of_points_test.cpp │ ├── circles_to_tree_test.cpp │ ├── convex_hull_test.cpp │ └── convex_polygon_test.cpp ├── strings │ ├── aho_corasick_test.cpp │ ├── eertree_test.cpp │ ├── min_cyclic_string_test.cpp │ ├── hashing_test.cpp │ ├── suffix_automaton_test.cpp │ ├── trie_test.cpp │ ├── kmp_test.cpp │ ├── manacher_test.cpp │ ├── z_function_test.cpp │ └── suffix_tree_test.cpp └── dynamic_programming │ ├── knuth_optimization_test.cpp │ ├── alien_trick_test.cpp │ └── dc_optimization_test.cpp ├── GEMP-Notebook.pdf ├── .gitignore ├── code ├── miscellaneous │ ├── pragma.h │ ├── change_stl.h │ ├── scheduling_jobs.h │ ├── fastio.h │ ├── random_function.h │ ├── parallel_binary_search.h │ ├── lis.h │ ├── counting_inversions.h │ ├── identify_pattern.h │ ├── sprague_grundy.h │ ├── automaton.h │ ├── mo_algorithm.h │ ├── histogram.h │ ├── kadane.h │ └── mo_with_update.h ├── math │ ├── gray_code.h │ ├── simpson_integration.h │ ├── floyd_cycle_finding.h │ ├── eulers_totient.h │ ├── division_trick.h │ ├── determinant.h │ ├── chinese_remainder_theorem.h │ ├── rank_matrix.h │ ├── gauss_xor.h │ ├── matrix.h │ ├── fraction.h │ ├── lagrange_poly.h │ ├── function_root_using_newton.h │ ├── gauss.h │ ├── karatsuba.h │ ├── lagrange.h │ ├── montgomery.h │ ├── prime.h │ └── catalan.h ├── theorems_and_formulas │ ├── primes.tex │ ├── eulers_totient.tex │ ├── manhattan_distance.tex │ ├── binomial_coefficients.tex │ └── formulas.tex ├── strings │ ├── min_cyclic_string.h │ ├── z_function.h │ ├── hashing.h │ ├── manacher.h │ └── kmp.h ├── dynamic_programming │ ├── alien_trick.h │ ├── dc_optimization.tex │ ├── knuth_optimization.h │ ├── dc_optimization.h │ └── knuth_optimization.tex ├── graph │ ├── kruskal.h │ ├── vertex_cover_in_tree.h │ ├── floyd_warshall.h │ ├── topological_sort.h │ ├── flow_with_demand.h │ ├── find_cycle_negative.h │ ├── dijkstra.h │ ├── centroid.h │ ├── bfs01.h │ ├── checking_bipartiteness_online.h │ ├── tree_id.h │ ├── prim.h │ ├── strongly_connected_component.h │ ├── bridge.h │ ├── eulerian_path.h │ ├── articulation_point.h │ ├── 2_sat.h │ ├── tree.h │ ├── graph_theorem.h │ └── mincut.h ├── data_structures │ ├── policy_based_tree.h │ ├── custom_hash.h │ ├── stack_query.h │ ├── multiset.h │ ├── distinct_values_in_range.h │ ├── dynamic_median.h │ ├── union_find_with_rollback.h │ ├── union_find_persistent.h │ ├── union_find.h │ ├── bit2d.h │ ├── bit_range.h │ ├── bit.h │ ├── permutation.h │ ├── bit2d_sparse.h │ ├── queue_query.h │ ├── line_container.h │ ├── sqrt_decomposition.h │ ├── rmq.h │ ├── sparse_table.h │ ├── lichao_tree.h │ ├── query_tree.h │ ├── segment_tree_2d.h │ ├── segment_tree_iterative.h │ ├── randomized_heap.h │ ├── segment_tree.h │ ├── merge_sort_tree.h │ └── segment_tree_persistent.h └── geometry │ ├── triangle.h │ ├── count_lattices.h │ ├── general_polygon.h │ ├── convex_hull_trick.h │ ├── convex_hull.h │ └── convex_polygon.h └── test_latex ├── generate_test_pdf.py └── test_content.tex /cheat_sheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PauloMiranda98/Competitive-Programming-Notebook/HEAD/cheat_sheet.pdf -------------------------------------------------------------------------------- /test/miscellaneous/fastio_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/fastio.h" 2 | 3 | int main(){ 4 | 5 | } -------------------------------------------------------------------------------- /test/miscellaneous/pragma_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/pragma.h" 2 | 3 | int main(){ 4 | 5 | } -------------------------------------------------------------------------------- /GEMP-Notebook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PauloMiranda98/Competitive-Programming-Notebook/HEAD/GEMP-Notebook.pdf -------------------------------------------------------------------------------- /test/miscellaneous/change_stl_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/change_stl.h" 2 | 3 | int main(){ 4 | 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | notebook.* 3 | test_latex/test_latex.* 4 | test_latex/test_pdf.pdf 5 | 6 | !test_latex/test_latex.tex -------------------------------------------------------------------------------- /code/miscellaneous/pragma.h: -------------------------------------------------------------------------------- 1 | #pragma GCC optimize("O3", "unroll-loops") 2 | #pragma GCC target("avx2") 3 | #pragma GCC target("popcnt") -------------------------------------------------------------------------------- /test/data_structures/custom_hash_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/custom_hash.h" 2 | int main(){ 3 | return 0; 4 | } -------------------------------------------------------------------------------- /test/data_structures/multiset_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/multiset.h" 2 | 3 | int main(){ 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /test/miscellaneous/random_function_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/random_function.h" 2 | 3 | int main(){ 4 | return 0; 5 | } -------------------------------------------------------------------------------- /test/graph/lca_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/lca.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/gauss_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/gauss.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/graph/lct_edge_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/lct_edge.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/determinant_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/determinant.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/gauss_xor_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/gauss_xor.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/rank_matrix_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/rank_matrix.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /code/math/gray_code.h: -------------------------------------------------------------------------------- 1 | int grayCode(int nth){ 2 | return nth ^ (nth >> 1); 3 | } 4 | int revGrayCode(int g){ 5 | int nth = 0; 6 | for (; g > 0; g >>= 1) 7 | nth ^= g; 8 | return nth; 9 | } -------------------------------------------------------------------------------- /test/graph/checking_bipartiteness_online_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/floyd_warshall.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/graph/floyd_warshall_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/checking_bipartiteness_online.h" 2 | void test(){ 3 | //No tests yet, then I'll add 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/graph/prufer_code_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/prufer_code.h" 2 | void test(){ 3 | assert(true); // AC: https://cses.fi/problemset/task/1134/ 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/fft_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/fft.h" 2 | void test1(){ 3 | assert(true); //https://codeforces.com/gym/101667/attachments problem H 4 | } 5 | int main() { 6 | test1(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/lagrange_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/lagrange.h" 2 | void test(){ 3 | assert(true); // AC: https://codeforces.com/gym/102878/problem/J 4 | } 5 | int main(){ 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/ntt_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/ntt.h" 2 | void test1(){ 3 | assert(true); //https://codeforces.com/gym/101667/attachments problem H 4 | } 5 | int main() { 6 | test1(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/lagrange_poly_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/lagrange_poly.h" 2 | void test(){ 3 | assert(true); // AC: https://codeforces.com/gym/103388/problem/A 4 | } 5 | int main(){ 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/graph/edmond_blossoms_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/edmond_blossoms.h" 2 | void test(){ 3 | assert(true); // AC: https://old.yosupo.jp/problem/general_matching 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/graph/find_cycle_negative_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/find_cycle_negative.h" 2 | void test(){ 3 | assert(true); // AC: https://cses.fi/problemset/task/1197/ 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/miscellaneous/automaton_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/automaton.h" 2 | void test(){ 3 | assert(true); // AC: Problem H: https://codeforces.com/gym/101635/ 4 | } 5 | int main() { 6 | test(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/math/function_root_using_newton_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/function_root_using_newton.h" 2 | void test1(){ 3 | assert(true); //https://vjudge.net/problem/UVA-10428 4 | } 5 | int main() { 6 | test1(); 7 | return 0; 8 | } 9 | -------------------------------------------------------------------------------- /test/data_structures/xor_trie_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/xor_trie.h" 2 | 3 | void test(){ 4 | assert(true); // AC in https://codeforces.com/contest/1658/problem/D2 5 | } 6 | 7 | int main(){ 8 | test(); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /test/geometry/point3d_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/point3d.h" 2 | void test(){ 3 | Point3d a(1, 1, 0), b(0, 3, 2); 4 | assert(eq(len(a), sqrt(2))); 5 | assert(eq(len(b), sqrt(13))); 6 | } 7 | int main(){ 8 | test(); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /test/math/modular_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/modular.h" 2 | void testDiv(){ 3 | for(int a=1; a<=1000; a++) 4 | for(int b=1; b<=1000; b++) 5 | assert( modMul(modDiv(a,b), b) == a); 6 | } 7 | int main(){ 8 | testDiv(); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /test/data_structures/union_find_persistent_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/union_find_persistent.h" 2 | 3 | void test(){ 4 | assert(true); // AC in https://cses.fi/problemset/task/2101/ 5 | } 6 | 7 | int main(){ 8 | test(); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /test/graph/kuhn_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/kuhn.h" 2 | void test(){ 3 | assert(true); // AC: https://codeforces.com/contest/590/problem/E 4 | assert(true); // AC: https://judge.yosupo.jp/problem/bipartitematching 5 | } 6 | int main() { 7 | test(); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /test/miscellaneous/parallel_binary_search_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/parallel_binary_search.h" 2 | 3 | bool test(int x){ 4 | return false; 5 | } 6 | 7 | void add(int k){ 8 | 9 | } 10 | 11 | void remove(int k){ 12 | 13 | } 14 | 15 | int main(){ 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/miscellaneous/sprague_grundy_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/sprague_grundy.h" 2 | void test(){ 3 | assert(solve({3, 3}) == "Second"); 4 | assert(solve({3, 2}) == "First"); 5 | assert(solve({1, 1, 1, 4}) == "First"); 6 | } 7 | int main() { 8 | test(); 9 | return 0; 10 | } -------------------------------------------------------------------------------- /test/graph/graph_theorem_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/graph_theorem.h" 2 | void test(){ 3 | assert(true); // AC: https://www.urionlinejudge.com.br/judge/pt/problems/view/1462 4 | assert(true); // AC: https://cses.fi/problemset/task/1697/ 5 | } 6 | int main() { 7 | test(); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /test/math/modular_int_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/modular_int.h" 2 | void testDiv(){ 3 | for(int a=1; a<=1000; a++){ 4 | for(int b=1; b<=1000; b++){ 5 | modInt a1 = a, b1=b; 6 | assert((a1/b1)*b1 == a1); 7 | } 8 | } 9 | } 10 | int main(){ 11 | testDiv(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/data_structures/query_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/query_tree.h" 2 | 3 | int getAnswer(){ 4 | return 0; 5 | } 6 | void rollback(int t){ 7 | 8 | } 9 | void insert(Query q){ 10 | 11 | } 12 | int getLastVersion(){ 13 | return 0; 14 | } 15 | 16 | int main(){ 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /code/theorems_and_formulas/primes.tex: -------------------------------------------------------------------------------- 1 | If $n = p_1^{e_1} \cdot p_2^{e_2} \cdots p_k^{e_k}$, then: 2 | 3 | Number of divisors is $d(n) = (e_1 + 1) \cdot (e_2 + 1) \cdots (e_k + 1)$. 4 | 5 | Sum of divisors is $\sigma(n) = \frac{p_1^{e_1 + 1} - 1}{p_1 - 1} \cdot \frac{p_2^{e_2 + 1} - 1}{p_2 - 1} \cdots \frac{p_k^{e_k + 1} - 1}{p_k - 1}$ 6 | -------------------------------------------------------------------------------- /test/math/montgomery_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/montgomery.h" 2 | void testMontgomery(){ 3 | u128 MOD = 10000000000000000007ULL; 4 | Montgomery mont(MOD); 5 | u128 x = mont.mult(1234567890123LL, 987654321098765LL); 6 | assert(x == 5278253119480564534ULL); 7 | } 8 | int main(){ 9 | testMontgomery(); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /test/graph/centroid_decomposition_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/centroid_decomposition.h" 2 | void test1(){ 3 | int n = 5, k = 2; 4 | CD::init(n); 5 | CD::addEdge(0, 1); 6 | CD::addEdge(1, 2); 7 | CD::addEdge(2, 3); 8 | CD::addEdge(2, 4); 9 | assert(CD::solve(k) == 4); 10 | } 11 | int main(){ 12 | test1(); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /test_latex/generate_test_pdf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | 4 | if __name__ == "__main__": 5 | os.system("latexmk -pdf test_latex.tex") 6 | os.system("mv test_latex.pdf test_pdf.pdf") 7 | os.system("mv test_latex.tex copy_test_latex.tex") 8 | os.system("rm test_latex.*") 9 | os.system("mv copy_test_latex.tex test_latex.tex") 10 | -------------------------------------------------------------------------------- /test/math/catalan_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/catalan.h" 2 | 3 | void test(){ 4 | assert(true); // AC: https://cses.fi/problemset/task/2064 5 | assert(true); // AC: https://cses.fi/problemset/task/2187 6 | assert(true); // AC: https://atcoder.jp/contests/abc205/tasks/abc205_e 7 | } 8 | 9 | int main(){ 10 | test(); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /test/math/simpson_integration_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/simpson_integration.h" 2 | double f(double x){ 3 | return 2*x; 4 | } 5 | const double EPS = 1e-9; 6 | 7 | void test(){ 8 | assert(abs(simpson_integration(0, 2) - 4) < EPS); 9 | assert(abs(simpson_integration(0, 4) - 16) < EPS); 10 | } 11 | 12 | int main(){ 13 | test(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /code/miscellaneous/change_stl.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | struct tipo{ 5 | int a, b; 6 | }; 7 | struct classcomp { 8 | bool operator() (const tipo& lhs, const tipo& rhs) const{ 9 | return lhs.a < rhs.a; 10 | } 11 | }; 12 | priority_queue, classcomp> st; 13 | priority_queue, greater> stMin; 14 | -------------------------------------------------------------------------------- /test/math/extended_euclidean_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/extended_euclidean.h" 2 | void testExtEuclidean(){ 3 | for (ll a = -100; a <= 100; a++){ 4 | for (ll b = -100; b <= 100; b++){ 5 | ll x, y; 6 | ll g = extGcd(a, b, x, y); 7 | assert(a * x + b * y == g); 8 | } 9 | } 10 | } 11 | int main(){ 12 | testExtEuclidean(); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /test/strings/aho_corasick_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/aho_corasick.h" 2 | 3 | void test1(){ 4 | assert(true); // AC: https://codeforces.com/contest/1437/problem/G 5 | assert(true); // AC: https://codeforces.com/contest/1400/problem/F 6 | assert(true); // AC: https://vjudge.net/problem/UVA-10679 7 | } 8 | 9 | int main() { 10 | test1(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /test/data_structures/union_find_with_rollback_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/union_find_with_rollback.h" 2 | 3 | void test(){ 4 | assert(true); // AC in https://codeforces.com/gym/102483/problem/F 5 | assert(true); // AC in https://vjudge.net/problem/UVA-11183 6 | assert(true); // AC in https://judge.yosupo.jp/problem/directedmst 7 | } 8 | 9 | int main(){ 10 | test(); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /test/strings/eertree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/eertree.h" 2 | void test1(){ 3 | assert(true); // AC: https://www.e-olymp.com/en/submissions/8183118 4 | assert(true); // AC: https://vjudge.net/problem/URAL-1960 5 | assert(true); // AC: https://vjudge.net/problem/URAL-2040 6 | assert(true); // AC: http://codeforces.com/contest/17/problem/E 7 | } 8 | int main() { 9 | test1(); 10 | return 0; 11 | } -------------------------------------------------------------------------------- /test/geometry/triangle_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/triangle.h" 2 | const double EPS = 1e-9; 3 | 4 | void test(){ 5 | Triangle t(3, 4, 5); 6 | auto [a, b, c] = t.angle(); 7 | 8 | assert(abs(t.area() - (3*4)/2) < EPS); 9 | assert(abs(a - 0.643501108793) < EPS); 10 | assert(abs(b - 0.9272952180021) < EPS); 11 | assert(abs(c - PI/2) < EPS); 12 | } 13 | int main(){ 14 | test(); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /test/math/gray_code_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/gray_code.h" 2 | #include 3 | using namespace std; 4 | void testGrayCode(){ 5 | int v[] = {0b000, 0b001, 0b011, 0b010, 0b110, 0b111, 0b101, 0b100}; 6 | for (int i = 0; i < 8; i++) 7 | assert(v[i] == grayCode(i)); 8 | for (int i = 0; i < 8; i++) 9 | assert(revGrayCode(v[i]) == i); 10 | } 11 | int main(){ 12 | testGrayCode(); 13 | return 0; 14 | } -------------------------------------------------------------------------------- /test_latex/test_content.tex: -------------------------------------------------------------------------------- 1 | $ 2 | \begin{vmatrix} 3 | n & nome & numero \; de \; poliminos \\ 4 | 1 & monominos & 1 \\ 5 | 2 & dominos & 1 \\ 6 | 3 & triminos & 2 \\ 7 | 4 & tetraminos & 5 \\ 8 | 5 & pentaminos & 12 \\ 9 | 6 & hexaminos & 35 \\ 10 | 7 & heptaminos & 108 \\ 11 | 8 & octaminos & 369 \\ 12 | 9 & nonominos & 1285 \\ 13 | 10 & decaminos & 4655 \\ 14 | 11 & undecaminos & 17073 \\ 15 | 12 & dodecaminos & 63600 16 | \end{vmatrix} 17 | $ 18 | -------------------------------------------------------------------------------- /test/miscellaneous/identify_pattern_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/identify_pattern.h" 2 | void test(){ 3 | assert(identifyPattern({1, 2, 3, 2, 2, 2, 2, 2, 2}) == pii(3, 1)); 4 | assert(identifyPattern({1, 2, 3, 2, 3, 2, 3, 2, 3}) == pii(1, 2)); 5 | assert(identifyPattern({1, 2, 3, 3, 2, 3, 3, 2, 3}) == pii(1, 3)); 6 | } 7 | 8 | int main() { 9 | ios_base::sync_with_stdio(false); cin.tie(NULL); 10 | test(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /code/math/simpson_integration.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | double f(double x); 4 | const int N = 1000000; 5 | double simpson_integration(double a, double b){ 6 | double h = (b - a) / N; 7 | double s = f(a) + f(b); // a = x_0 and b = x_2n 8 | for (int i = 1; i <= N - 1; ++i) { // Refer to final Simpson's formula 9 | double x = a + h * i; 10 | s += f(x) * ((i & 1) ? 4 : 2); 11 | } 12 | s *= h / 3; 13 | return s; 14 | } -------------------------------------------------------------------------------- /test/geometry/circle_area_union_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/circle_area_union.h" 2 | 3 | void testCircle(){ 4 | vector vc; 5 | vc.emplace_back(0, 0, 1.4142135624); 6 | vc.emplace_back(0, 2, 1.4142135624); 7 | vc.emplace_back(2, 0, 1.4142135624); 8 | vc.emplace_back(2, 2, 1.4142135624); 9 | double ans = circle_union(vc); 10 | assert(eq(ans, 20.566370614837)); 11 | } 12 | 13 | int main(){ 14 | testCircle(); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /test/math/sieve_and_primes_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/sieve_and_primes.h" 2 | 3 | void testIsPrime(){ 4 | sieve(10000000); 5 | for (ll prime : {1993LL, 1997LL, 1999LL, 2017LL, 7823LL, 7829LL, 998244353LL, 1000000007LL, 1000000009LL, 87178291199LL}) 6 | assert(isPrime(prime) == true); 7 | for (ll noPrime : {7875, 7878, 4623, 4641, 1000000005}) 8 | assert(isPrime(noPrime) == false); 9 | } 10 | 11 | int main(){ 12 | testIsPrime(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/math/division_trick_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/division_trick.h" 2 | void test1(){ 3 | for(int i=1; i<=1000; i++) 4 | assert(bruteForce(i) == divisionTrick(i)); 5 | 6 | assert(bruteForce(1e7) == divisionTrick(1e7)); 7 | assert(bruteForce(1e7 + 5) == divisionTrick(1e7 + 5)); 8 | assert(bruteForce(1e6 + 7) == divisionTrick(1e6 + 7)); 9 | assert(true); // https://cses.fi/problemset/task/1082 10 | } 11 | int main() { 12 | test1(); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /code/strings/min_cyclic_string.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | string min_cyclic_string(string s){ 4 | s += s; 5 | int n = s.size(); 6 | int i = 0, ans = 0; 7 | while (i < n / 2){ 8 | ans = i; 9 | int j = i + 1, k = i; 10 | while (j < n && s[k] <= s[j]){ 11 | if (s[k] < s[j]) 12 | k = i; 13 | else 14 | k++; 15 | j++; 16 | } 17 | while (i <= k) 18 | i += j - k; 19 | } 20 | return s.substr(ans, n / 2); 21 | } -------------------------------------------------------------------------------- /code/dynamic_programming/alien_trick.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define F first 3 | #define S second 4 | using namespace std; 5 | using ll = long long; 6 | using pll = pair; 7 | pll solveDP(ll C); 8 | ll solveMax(int k){ 9 | ll lo = 0, hi=1e16, ans=1e16; 10 | while(lo <= hi){ 11 | ll mid = (lo+hi)>>1; 12 | if(solveDP(mid).S <= k){ 13 | ans = mid; 14 | hi = mid - 1; 15 | }else{ 16 | lo = mid + 1; 17 | } 18 | } 19 | return solveDP(ans).F + k*ans; 20 | } 21 | -------------------------------------------------------------------------------- /test/geometry/count_lattices_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/count_lattices.h" 2 | void testCountLattices(){ 3 | Fraction k, b; 4 | k = 1; 5 | b = 0; 6 | assert(count_lattices(k, b, 4) == 6); 7 | 8 | k = 1; 9 | b = 1; 10 | assert(count_lattices(k, b, 4) == 10); 11 | 12 | k = -1; 13 | b = 4; 14 | assert(count_lattices(k, b, 4) == 10); 15 | 16 | k = {5, 2}; 17 | b = 2; 18 | assert(count_lattices(k, b, 4) == 22); 19 | 20 | } 21 | 22 | int main(){ 23 | testCountLattices(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /code/graph/kruskal.h: -------------------------------------------------------------------------------- 1 | #include "../data_structures/union_find.h" 2 | typedef long long ll; 3 | struct Edge{ 4 | int u, v; ll w; 5 | Edge(){} 6 | Edge(int u1, int v1, ll w1):u(u1), v(v1), w(w1){} 7 | }; 8 | ll kruskal(vector v, int nVet){ 9 | ll cost = 0; 10 | UnionFind uf(nVet); 11 | sort(v.begin(), v.end(), [&](Edge a, Edge b){ 12 | return a.w < b.w; 13 | }); 14 | for(Edge &e: v){ 15 | if(!uf.isSame(e.u, e.v)){ 16 | cost += e.w; 17 | uf.join(e.u, e.v); 18 | } 19 | } 20 | return cost; 21 | } -------------------------------------------------------------------------------- /code/miscellaneous/scheduling_jobs.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | struct Job { 5 | int t, c, idx; 6 | Job(int t1=0, int c1=0, int i=0):t(t1), c(c1), idx(i){} 7 | }; 8 | //Penalty functions fi(t) = c[i]*t 9 | bool cmp1(Job a, Job b){ 10 | return a.c*(ll)b.t > b.c*(ll)a.t; 11 | } 12 | //Penalty functions fi(t) = c[i]*e^(alfa*t) 13 | const double alfa = 2; 14 | const double EPS = 1e-9; 15 | bool cmp2(Job a, Job b){ 16 | return (1 - exp(alfa*a.t))/a.c > (1 - exp(alfa*b.t))/b.c + EPS; 17 | } -------------------------------------------------------------------------------- /test/geometry/convex_hull_trick_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/convex_hull_trick.h" 2 | 3 | void testAddAndGet(){ 4 | ConvexHullTrick cht; 5 | cht.add_line(-1, 10); 6 | cht.add_line(0, -6); 7 | cht.add_line(2, 30); 8 | 9 | for (int x = -100; x >= -18; x--) 10 | assert(cht.get(x) == (2 * x + 30)); 11 | for (int x = -18; x <= 16; x++) 12 | assert(cht.get(x) == (0 * x - 6)); 13 | for (int x = 16; x <= 100; x++) 14 | assert(cht.get(x) == (-1 * x + 10)); 15 | } 16 | 17 | int main(){ 18 | testAddAndGet(); 19 | return 0; 20 | } -------------------------------------------------------------------------------- /test/strings/min_cyclic_string_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/min_cyclic_string.h" 2 | string brute(string s){ 3 | int n = s.size(); 4 | string mn = s; 5 | s += s; 6 | for(int i=0; i 2 | int readInt () { 3 | bool minus = false; 4 | int result = 0; 5 | char ch; 6 | ch = getchar(); 7 | while (true) { 8 | if (ch == '-') break; 9 | if (ch >= '0' && ch <= '9') break; 10 | ch = getchar(); 11 | } 12 | if (ch == '-') minus = true; else result = ch-'0'; 13 | while (true) { 14 | ch = getchar(); 15 | if (ch < '0' || ch > '9') break; 16 | result = result*10 + (ch - '0'); 17 | } 18 | if (minus) 19 | return -result; 20 | else 21 | return result; 22 | } 23 | -------------------------------------------------------------------------------- /test/data_structures/dynamic_median_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/dynamic_median.h" 2 | const double EPS = 1e-9; 3 | 4 | void testAddAndGet(){ 5 | DinamicMedian md; 6 | md.push(10); 7 | md.push(50); 8 | md.push(5); 9 | assert(abs(md.median() - 10) < EPS); 10 | 11 | md.push(5); 12 | assert(abs(md.median() - 7.5) < EPS); 13 | 14 | md.push(2); 15 | assert(abs(md.median() - 5) < EPS); 16 | 17 | md.push(50); 18 | md.push(30); 19 | assert(abs(md.median() - 10) < EPS); 20 | } 21 | 22 | int main(){ 23 | testAddAndGet(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /code/dynamic_programming/dc_optimization.tex: -------------------------------------------------------------------------------- 1 | Reduces the complexity from $O(n^2k)$ to $O(nk\log n)$ of PD's in the following ways (and other variants): 2 | \begin{equation} 3 | dp[n][k] = \max_{0 \leq i < n}(dp[i][k-1] + C[i+1][n]), \; base \; case: \; dp[0][j], dp[i][0] 4 | \end{equation} 5 | \begin{itemize} 6 | \itemsep0em 7 | \item $C[i][j] = $ the cost only depends on $i$ and $j$. 8 | \item $opt[n][k] = i$ is the optimal value that maximizes $dp[n][k]$. 9 | \end{itemize} 10 | It is necessary that $opt$ is increasing along each column: $opt[j][k] \leq opt[j+1][k]$. -------------------------------------------------------------------------------- /test/miscellaneous/histogram_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/histogram.h" 2 | void test1(){ 3 | assert(histogram({1, 1, 1, 1, 1}) == 5); 4 | assert(histogram({1, 2, 3, 2, 1}) == 6); 5 | assert(histogram({1}) == 1); 6 | assert(histogram({1, 2, 3, 4, 20}) == 20); 7 | 8 | assert(true); // AC: https://leetcode.com/problems/largest-rectangle-in-histogram/ 9 | assert(true); // AC: https://cses.fi/problemset/task/1142/ 10 | 11 | assert(true); // AC: https://cses.fi/problemset/task/1147/ 12 | } 13 | int main() { 14 | test1(); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /code/data_structures/policy_based_tree.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace __gnu_pbds; 5 | using namespace std; 6 | template using ordered_set = tree, rb_tree_tag, tree_order_statistics_node_update>; 7 | template using ordered_map = tree, rb_tree_tag, tree_order_statistics_node_update>; 8 | 9 | //order_of_key (k) : Number of items strictly smaller than k . 10 | //find_by_order(k) : K-th element in a set (counting from zero). -------------------------------------------------------------------------------- /test/data_structures/bit2d_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/bit2d.h" 2 | 3 | void testAddAndGet(){ 4 | Bit2d bit(10, 10); 5 | bit.add(1, 1, 5); 6 | bit.add(2, 1, 3); 7 | bit.add(1, 3, 2); 8 | 9 | assert(bit.get(1, 1) == 5); 10 | assert(bit.get(2, 1) == 8); 11 | assert(bit.get(1, 3) == 7); 12 | assert(bit.get(3, 3) == 10); 13 | 14 | assert(bit.get(2, 2, 3, 3) == 0); 15 | assert(bit.get(1, 1, 1, 1) == 5); 16 | assert(bit.get(2, 1, 2, 1) == 3); 17 | assert(bit.get(1, 3, 1, 3) == 2); 18 | } 19 | 20 | int main(){ 21 | testAddAndGet(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/graph/eulerian_path_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/eulerian_path.h" 2 | void test(){ 3 | assert(true); // AC: https://codeforces.com/gym/100812/problem/C 4 | assert(true); // AC: https://www.urionlinejudge.com.br/judge/pt/problems/view/1671 5 | assert(true); // AC: https://codeforces.com/contest/1511/problem/D 6 | assert(true); // AC: https://cses.fi/problemset/task/1691/ 7 | assert(true); // AC: https://cses.fi/problemset/task/1692/ 8 | assert(true); // AC: https://cses.fi/problemset/task/1693/ 9 | } 10 | int main() { 11 | test(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/math/eulers_totient_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/eulers_totient.h" 2 | #include 3 | using namespace std; 4 | void testNthPhi(){ 5 | int phi[24] = {0, 1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8, 12, 10, 22}; 6 | for (int i = 0; i < 24; i++) 7 | assert(phi[i] == nthPhi(i)); 8 | } 9 | void testPhiFrom1ToN(){ 10 | int N = 10000; 11 | vector phi = phiFrom1toN(N); 12 | for (int i = 0; i <= N; i++) 13 | assert(phi[i] == nthPhi(i)); 14 | } 15 | int main(){ 16 | testNthPhi(); 17 | testPhiFrom1ToN(); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /code/data_structures/custom_hash.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | struct custom_hash { 4 | static uint64_t splitmix64(uint64_t x) { 5 | x += 0x9e3779b97f4a7c15; 6 | x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; 7 | x = (x ^ (x >> 27)) * 0x94d049bb133111eb; 8 | return x ^ (x >> 31); 9 | } 10 | size_t operator()(uint64_t x) const { 11 | static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count(); 12 | return splitmix64(x + FIXED_RANDOM); 13 | } 14 | }; 15 | typedef unordered_map umap; 16 | -------------------------------------------------------------------------------- /code/data_structures/stack_query.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | struct StackQuery{ 4 | typedef int t_stack; 5 | stack> st; 6 | t_stack cmp(t_stack a, t_stack b){ 7 | return min(a, b); 8 | } 9 | void push(t_stack x){ 10 | t_stack new_value = st.empty() ? x : cmp(x, st.top().second); 11 | st.push({x, new_value}); 12 | } 13 | void pop(){ 14 | st.pop(); 15 | } 16 | t_stack top(){ 17 | return st.top().first; 18 | } 19 | t_stack query(){ 20 | return st.top().second; 21 | } 22 | t_stack size(){ 23 | return st.size(); 24 | } 25 | }; -------------------------------------------------------------------------------- /test/math/chinese_remainder_theorem_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/chinese_remainder_theorem.h" 2 | void test1CRT(){ 3 | vector m = {5, 6, 7, 11}; 4 | vector a = {3, 3, 1, 0}; 5 | assert(CRT::solve(a, m) == 1023); 6 | } 7 | void test2CRT(){ 8 | vector m = {2, 3, 4, 6, 11}; 9 | vector a(m.size()); 10 | for (int test = 0; test <= 100; test++){ 11 | for (int i = 0; i < m.size(); i++) 12 | a[i] = test % m[i]; 13 | ll ans = CRT::solve(a, m); 14 | assert(test == ans); 15 | } 16 | } 17 | int main(){ 18 | test1CRT(); 19 | test2CRT(); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /test/data_structures/bit2d_sparse_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/bit2d_sparse.h" 2 | 3 | void testAddAndGet(){ 4 | Bit2d::add(1, 1); 5 | Bit2d::add(2, 1); 6 | Bit2d::add(1, 3); 7 | 8 | assert(Bit2d::get(1, 1) == 1); 9 | assert(Bit2d::get(2, 1) == 2); 10 | assert(Bit2d::get(1, 3) == 2); 11 | assert(Bit2d::get(3, 3) == 3); 12 | 13 | assert(Bit2d::get(2, 2, 3, 3) == 0); 14 | assert(Bit2d::get(1, 1, 1, 1) == 1); 15 | assert(Bit2d::get(2, 1, 2, 1) == 1); 16 | assert(Bit2d::get(1, 3, 1, 3) == 1); 17 | } 18 | 19 | int main(){ 20 | testAddAndGet(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/data_structures/bit_range_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/bit_range.h" 2 | 3 | void testAddAndGet(){ 4 | BitRange bit(10); 5 | bit.add(1, 1, 2); 6 | bit.add(1, 2, 1); 7 | bit.add(2, 4, 3); 8 | 9 | assert(bit.get(1, 1) == 3); 10 | assert(bit.get(2, 2) == 4); 11 | assert(bit.get(3, 3) == 3); 12 | assert(bit.get(4, 4) == 3); 13 | assert(bit.get(5, 5) == 0); 14 | 15 | assert(bit.get(1) == 3); 16 | assert(bit.get(2) == 7); 17 | assert(bit.get(3) == 10); 18 | assert(bit.get(4) == 13); 19 | assert(bit.get(5) == 13); 20 | } 21 | 22 | int main(){ 23 | testAddAndGet(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /code/math/floyd_cycle_finding.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int f(int x); 4 | typedef pair pii; 5 | pii floydCycleFinding(int x0){ 6 | int tortoise = f(x0), hare = f(f(x0)); 7 | while(tortoise != hare){ 8 | tortoise = f(tortoise); 9 | hare = f(f(hare)); 10 | } 11 | int mu = 0; 12 | hare = x0; 13 | while(tortoise != hare){ 14 | tortoise = f(tortoise); 15 | hare = f(hare); 16 | mu++; 17 | } 18 | int lambda = 1; 19 | hare = f(tortoise); 20 | while(tortoise != hare){ 21 | hare = f(hare); 22 | lambda++; 23 | } 24 | return pii(mu, lambda); 25 | } 26 | -------------------------------------------------------------------------------- /test/math/floyd_cycle_finding_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/floyd_cycle_finding.h" 2 | const int MAXN = 10010; 3 | int g[MAXN], tmp[MAXN]; 4 | int f(int x){ 5 | return g[x]; 6 | } 7 | void test(){ 8 | int T=5; 9 | srand(2020); 10 | while(T--){ 11 | for(int i=0; i 2 | using namespace std; 3 | const int MAXN = 200010; 4 | int dp[MAXN][2]; 5 | vector adj[MAXN]; 6 | // vertexCover(node current, free to choose, dad) 7 | int vertexCover(int u, bool color=true, int p=-1){ 8 | if(dp[u][color] != -1) 9 | return dp[u][color]; 10 | int case1 = 1, case2 = 0; 11 | for(int to: adj[u]){ 12 | if(to == p) continue; 13 | case1 += vertexCover(to, true, u); 14 | case2 += vertexCover(to, false, u); 15 | } 16 | if(color) 17 | return dp[u][color] = min(case1, case2); 18 | else 19 | return dp[u][color] = case1; 20 | } -------------------------------------------------------------------------------- /code/theorems_and_formulas/eulers_totient.tex: -------------------------------------------------------------------------------- 1 | If p is a prime number: $\phi (p) = p - 1$ and $\phi(p^k) = p^k - p^{k-1}$ 2 | 3 | If a and b are relatively prime, then: $\phi(a b) = \phi(a) \cdot \phi(b)$ 4 | 5 | In general: $\phi(ab) = \phi(a) \cdot \phi(b) \cdot \dfrac{gcd(a, b)}{\phi(gcd(a, b))}$ 6 | 7 | This interesting property was established by Gauss: $\sum_{d|n} \phi{(d)} = n$, Here the sum is over all positive divisors d of n. 8 | 9 | Euler's theorem: $a^{\phi(m)} \equiv 1 \pmod m$, if a and m are relatively prime. 10 | 11 | Generalization: $a^{n}\equiv a^{\phi(m)+[n \bmod \phi(m)]} \mod m$, for arbitrary a, m and n $\ge log_2(m)$. 12 | -------------------------------------------------------------------------------- /test/miscellaneous/polyominoes_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/polyominoes.h" 2 | 3 | void test(){ 4 | buildPolyominoes(); 5 | assert(polyominoes[1].size() == 1); 6 | assert(polyominoes[2].size() == 2); 7 | assert(polyominoes[3].size() == 6); 8 | assert(polyominoes[4].size() == 19); 9 | assert(polyominoes[5].size() == 63); 10 | assert(polyominoes[6].size() == 216); 11 | assert(polyominoes[7].size() == 760); 12 | assert(polyominoes[8].size() == 2725); 13 | assert(polyominoes[9].size() == 9910); 14 | assert(polyominoes[10].size() == 36446); 15 | } 16 | 17 | int main() { 18 | test(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /test/math/linear_sequence_with_berlekamp_massey_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/linear_sequence_with_berlekamp_massey.h" 2 | void test1(){ 3 | assert(true); // AC: https://www.codechef.com/problems/RNG 4 | } 5 | int fib(int n){ 6 | vector fib(n + 1); 7 | fib[0] = 0; 8 | fib[1] = 1; 9 | for(int i=2; i<=n; i++){ 10 | fib[i] = (fib[i-1] + fib[i-2])%MOD; 11 | } 12 | return fib[n]; 13 | } 14 | void test2(){ 15 | for(int i=0; i<=100; i++){ 16 | int f1 = LinearSeq::findElementInPositionN({0, 1, 1, 2}, i); 17 | assert(f1 == fib(i)); 18 | } 19 | } 20 | int main(){ 21 | test1(); 22 | test2(); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/data_structures/union_find_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/union_find.h" 2 | 3 | void testFindAndJoin(){ 4 | UnionFind uf(10); 5 | for (int i = 0; i <= 10; i++) 6 | assert(uf.find(i) == i); 7 | uf.join(1, 3); 8 | assert(uf.find(1) == uf.find(3)); 9 | uf.join(3, 4); 10 | assert(uf.find(1) == uf.find(4)); 11 | assert(uf.find(3) == uf.find(4)); 12 | uf.join(8, 10); 13 | assert(uf.find(8) == uf.find(10)); 14 | for (int i = 0; i < 10; i++) 15 | uf.join(i, i + 1); 16 | for (int i = 0; i <= 10; i++) 17 | assert(uf.find(i) == uf.find(0)); 18 | } 19 | 20 | int main(){ 21 | testFindAndJoin(); 22 | return 0; 23 | } -------------------------------------------------------------------------------- /test/graph/flow_with_demand_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/flow_with_demand.h" 2 | typedef pair pii; 3 | void test1(){ 4 | MaxFlowEdgeDemands mfd(4); 5 | mfd.addEdge(0, 1, 5, 3); 6 | mfd.addEdge(0, 2, 2, 2); 7 | mfd.addEdge(1, 3, 1, 2); 8 | mfd.addEdge(2, 3, 5, 0); 9 | 10 | assert(mfd.solve(0, 3) == false); 11 | } 12 | 13 | void test2(){ 14 | MaxFlowEdgeDemands mfd(4); 15 | mfd.addEdge(0, 1, 3, 2); 16 | mfd.addEdge(0, 2, 2, 2); 17 | mfd.addEdge(1, 3, 1, 2); 18 | mfd.addEdge(2, 3, 5, 0); 19 | 20 | assert(mfd.solve(0, 3) == true); 21 | } 22 | 23 | int main(){ 24 | test1(); 25 | test2(); 26 | return 0; 27 | } -------------------------------------------------------------------------------- /code/miscellaneous/random_function.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | mt19937 rng((int) std::chrono::steady_clock::now().time_since_epoch().count()); 4 | inline int rand(int l, int r){ 5 | return uniform_int_distribution(l, r)(rng); 6 | } 7 | inline double rand(double l, double r){ 8 | return uniform_real_distribution(l, r)(rng); 9 | } 10 | mt19937_64 rng_64((int) std::chrono::steady_clock::now().time_since_epoch().count()); 11 | inline int64_t rand(int64_t l, int64_t r){ 12 | return uniform_int_distribution(l, r)(rng_64); 13 | } 14 | void randomShuffle(vector &v){ 15 | shuffle(v.begin(), v.end(), rng); 16 | } 17 | -------------------------------------------------------------------------------- /test/graph/dinic_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/dinic.h" 2 | typedef pair pii; 3 | void test1(){ 4 | Dinic dinic; 5 | dinic.init(10); 6 | for (int i = 1; i <= 4; i++) 7 | dinic.addEdge(0, i, 1); 8 | 9 | dinic.addEdge(1, 5, 1); 10 | dinic.addEdge(2, 5, 1); 11 | dinic.addEdge(2, 6, 1); 12 | dinic.addEdge(2, 7, 1); 13 | dinic.addEdge(3, 6, 1); 14 | dinic.addEdge(3, 7, 1); 15 | dinic.addEdge(3, 8, 1); 16 | dinic.addEdge(4, 7, 1); 17 | 18 | for (int i = 5; i <= 8; i++) 19 | dinic.addEdge(i, 9, 1); 20 | int ans = dinic.maxFlow(0, 9); 21 | assert(ans == 4); 22 | } 23 | int main(){ 24 | test1(); 25 | return 0; 26 | } -------------------------------------------------------------------------------- /test/graph/2_sat_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/2_sat.h" 2 | typedef pair pii; 3 | //(A) = (0) 4 | //(B) = (1) 5 | //(C) = (2) 6 | const int A = 0, B = 1, C = 2; 7 | 8 | void test(){ 9 | //(A v B) ^ (~A v ~C) ^ (B v C) 10 | SAT sat(3); 11 | sat.addOr(A, B); 12 | sat.addOr(~A, ~C); 13 | sat.addOr(B, C); 14 | vector vans = sat.solve2SAT(); 15 | bool ans = true; 16 | ans &= (vans[A] | vans[B]); 17 | ans &= ((!vans[A]) | (!vans[C])); 18 | ans &= (vans[B] | vans[C]); 19 | assert(ans); 20 | } 21 | void test2(){ 22 | assert(true); // AC: https://cses.fi/problemset/task/1684/ 23 | } 24 | int main(){ 25 | test(); 26 | return 0; 27 | } -------------------------------------------------------------------------------- /test/graph/hungarian_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/hungarian.h" 2 | void test1(){ 3 | int n = 3; 4 | vector> mat(n, vector(n)); 5 | mat[0] = {2, 5, 10}; 6 | mat[1] = {1, 5, 3}; 7 | mat[2] = {10, 20, 10}; 8 | auto ans = solve(mat); 9 | assert(ans.second == 16); 10 | int sum = 0; 11 | for(int i=0; i 2 | using namespace std; 3 | // z[i] is the length of the longest common prefix between s[0..(n-1)] and the suffix of s[i..(n-1)]. 4 | // z[0] is generally not well defined. 5 | // "aaabaab" - [0,2,1,0,2,1,0] 6 | // "abacaba" - [0,0,1,0,3,0,1] 7 | vector z_function(string s) { 8 | int n = (int) s.length(); 9 | vector z(n); 10 | for (int i = 1, l = 0, r = 0; i < n; i++){ 11 | if (i <= r) 12 | z[i] = min (r - i + 1, z[i - l]); 13 | while (i + z[i] < n && s[z[i]] == s[i + z[i]]) 14 | z[i]++; 15 | if (i + z[i] - 1 > r) 16 | l = i, r = i + z[i] - 1; 17 | } 18 | return z; 19 | } 20 | -------------------------------------------------------------------------------- /code/geometry/triangle.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long double ld; 4 | const ld PI = acosl(-1); 5 | struct Triangle{ 6 | ld a, b, c; 7 | Triangle(){} 8 | Triangle(ld a1, ld b1, ld c1):a(a1), b(b1), c(c1){ 9 | fix(); 10 | } 11 | ld area(){ 12 | ld s = (a + b + c)/2; 13 | return sqrtl(s*(s-a)*(s-b)*(s-c)); 14 | } 15 | void fix(){ 16 | if(a > b) swap(a, b); 17 | if(a > c) swap(a, c); 18 | if(b > c) swap(b, c); 19 | } 20 | tuple angle(){ 21 | fix(); 22 | ld h = (2*area())/c; 23 | ld aa = asin(h/b); 24 | ld bb = asin(h/a); 25 | return {aa, bb, PI - aa - bb}; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /test/geometry/nearest_pair_of_points_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/nearest_pair_of_points.h" 2 | const double EPS = 1e-6; 3 | void test1(){ 4 | vector v; 5 | for(int i=0; i<100; i++) 6 | v.emplace_back(rand(), rand()); 7 | 8 | NearestPairOfPoints::solve(v); 9 | auto ans = NearestPairOfPoints::mindist; 10 | 11 | double mn = 1e20; 12 | for(int i=0; i<100; i++) 13 | for(int j=i+1; j<100; j++) 14 | mn = min(mn, sqrt((v[i].x - v[j].x)*(v[i].x - v[j].x) + (v[i].y - v[j].y)*(v[i].y - v[j].y))); 15 | assert(abs(ans-mn) < EPS); 16 | } 17 | int main(){ 18 | srand(98); 19 | for(int i=0; i<5; i++) 20 | test1(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /test/miscellaneous/lis_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/lis.h" 2 | vector v; 3 | int n; 4 | int brute(int i, int x){ 5 | if(i == n) 6 | return 0; 7 | if(v[i] > x) 8 | return max(brute(i+1, x), 1 + brute(i+1, v[i])); 9 | else 10 | return brute(i+1, x); 11 | } 12 | void test(){ 13 | srand(time(0)); 14 | n = 18; 15 | v.resize(n); 16 | for (int i = 0; i < n; i++) 17 | v[i] = rand() % 100000; 18 | vector ans = lis(v); 19 | assert((int)ans.size() == brute(0, -0x3f3f3f3f)); 20 | 21 | } 22 | int main(){ 23 | for(int i=0; i<10; i++) 24 | test(); 25 | 26 | assert(true); // AC: https://cses.fi/problemset/task/1162/ 27 | return 0; 28 | } -------------------------------------------------------------------------------- /test/graph/prim_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/prim.h" 2 | void test1(){ 3 | int n = 5; 4 | Prim::init(n); 5 | Prim::addEdge(0, 1, 15); 6 | Prim::addEdge(0, 2, 10); 7 | Prim::addEdge(1, 2, 1); 8 | Prim::addEdge(2, 3, 3); 9 | Prim::addEdge(1, 3, 5); 10 | Prim::addEdge(3, 4, 20); 11 | assert(Prim::solve() == 34); 12 | } 13 | void test2(){ 14 | int n = 5; 15 | Prim::init(n); 16 | Prim::addEdge(0, 1, 1); 17 | Prim::addEdge(0, 2, 10); 18 | Prim::addEdge(0, 3, 1); 19 | Prim::addEdge(1, 2, 1); 20 | Prim::addEdge(1, 3, 10); 21 | Prim::addEdge(2, 3, 1); 22 | assert(Prim::solve() == 3); 23 | } 24 | int main(){ 25 | test1(); 26 | test2(); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /code/data_structures/multiset.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | template 4 | class MultiSet{ 5 | map mp; 6 | int sz = 0; 7 | public: 8 | MultiSet(){} 9 | void insert(T x){ 10 | sz++; 11 | mp[x]++; 12 | } 13 | void erase(T x){ 14 | sz--; 15 | mp[x]--; 16 | if(mp[x] == 0){ 17 | mp.erase(x); 18 | } 19 | } 20 | int count(T x){ 21 | auto it = mp.find(x); 22 | if(it == mp.end()) 23 | return 0; 24 | return it->second; 25 | } 26 | int min(){ 27 | return mp.begin()->first; 28 | } 29 | int max(){ 30 | return mp.rbegin()->first; 31 | } 32 | int size(){ 33 | return sz; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /test/data_structures/lichao_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/lichao_tree.h" 2 | 3 | void testAddAndGet(){ 4 | LiChaoTree lct(-100, 100); 5 | lct.add(1, -10); 6 | lct.add(-2, -30); 7 | 8 | for (int x = -100; x >= -7; x--) 9 | assert(lct.get(x) == (-2 * x - 30)); 10 | for (int x = -6; x <= 100; x++) 11 | assert(lct.get(x) == (1 * x - 10)); 12 | 13 | lct.add(0, 6); 14 | for (int x = -100; x >= -18; x--) 15 | assert(lct.get(x) == (-2 * x - 30)); 16 | for (int x = -18; x <= 16; x++) 17 | assert(lct.get(x) == (0 * x + 6)); 18 | for (int x = 16; x <= 100; x++) 19 | assert(lct.get(x) == (1 * x - 10)); 20 | } 21 | 22 | int main(){ 23 | testAddAndGet(); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /code/geometry/count_lattices.h: -------------------------------------------------------------------------------- 1 | #include "../../code/math/fraction.h" 2 | Fraction f_1 = 1; 3 | //Calculates number of integer points (x,y) such for 0<=x= f_1 || b >= f_1) { 11 | cnt += (fk * (n - 1) + 2 * fb) * n / 2; 12 | k = k - Fraction(fk, 1); 13 | b = b - Fraction(fb, 1); 14 | } 15 | auto t = k * Fraction(n, 1) + b; 16 | auto ft = (f_type)t; 17 | if (ft >= 1) { 18 | cnt += count_lattices(f_1 / k, (t - Fraction((f_type)t, 1)) / k, (f_type)t); 19 | } 20 | return cnt; 21 | } 22 | -------------------------------------------------------------------------------- /code/math/eulers_totient.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int nthPhi(int n){ 4 | int result = n; 5 | for (int i = 2; i <= n / i; i++){ 6 | if (n % i == 0){ 7 | while (n % i == 0) 8 | n /= i; 9 | result -= result / i; 10 | } 11 | } 12 | if (n > 1) 13 | result -= result / n; 14 | return result; 15 | } 16 | vector phiFrom1toN(int n){ 17 | vector vPhi(n + 1); 18 | vPhi[0] = 0; 19 | vPhi[1] = 1; 20 | for (int i = 2; i <= n; i++) 21 | vPhi[i] = i; 22 | for (int i = 2; i <= n; i++){ 23 | if (vPhi[i] == i){ 24 | for (int j = i; j <= n; j += i) 25 | vPhi[j] -= vPhi[j] / i; 26 | } 27 | } 28 | return vPhi; 29 | } -------------------------------------------------------------------------------- /test/graph/kruskal_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/kruskal.h" 2 | void test1(){ 3 | int n = 5; 4 | vector v; 5 | v.emplace_back(1, 2, 15); 6 | v.emplace_back(1, 3, 10); 7 | v.emplace_back(2, 3, 1); 8 | v.emplace_back(3, 4, 3); 9 | v.emplace_back(2, 4, 5); 10 | v.emplace_back(4, 5, 20); 11 | assert(kruskal(v, n) == 34); 12 | } 13 | void test2(){ 14 | int n = 5; 15 | vector v; 16 | v.emplace_back(1, 2, 1); 17 | v.emplace_back(1, 3, 10); 18 | v.emplace_back(1, 4, 1); 19 | v.emplace_back(2, 3, 1); 20 | v.emplace_back(2, 4, 10); 21 | v.emplace_back(3, 4, 1); 22 | assert(kruskal(v, n) == 3); 23 | } 24 | int main(){ 25 | test1(); 26 | test2(); 27 | return 0; 28 | } -------------------------------------------------------------------------------- /test/data_structures/randomized_heap_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/randomized_heap.h" 2 | 3 | void test1(){ 4 | RandomizedHeap rd; 5 | priority_queue, greater> pq; 6 | srand(98); 7 | for(int i=0; i<50000; i++){ 8 | int op = rand()%3; 9 | assert(pq.size() == rd.size()); 10 | 11 | if(op == 0){ 12 | int x = rand(); 13 | pq.push(x); 14 | rd.push(x); 15 | }else if(op == 1){ 16 | if(pq.size() > 0){ 17 | pq.pop(); 18 | rd.pop(); 19 | } 20 | }else if(op == 2){ 21 | if(pq.size() > 0) 22 | assert(pq.top() == rd.top()); 23 | } 24 | } 25 | } 26 | int main() { 27 | 28 | return 0; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /test/math/linear_sequence_with_reeds_sloane_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/linear_sequence_with_reeds_sloane.h" 2 | void test1(){ 3 | assert(true); // AC: https://codeforces.com/gym/103960/problem/K 4 | } 5 | const int MOD = 1e9; 6 | int fib(int n){ 7 | vector fib(n + 1); 8 | fib[0] = 0; 9 | fib[1] = 1; 10 | for(int i=2; i<=n; i++){ 11 | fib[i] = (fib[i-1] + fib[i-2])%MOD; 12 | } 13 | return fib[n]; 14 | } 15 | void test2(){ 16 | for(int i=0; i<=100; i++){ 17 | vector v = {0, 1, 1, 2}; 18 | LinearRecurrence lr(v, MOD, false); 19 | int f1 = lr.calc(i); 20 | assert(f1 == fib(i)); 21 | } 22 | } 23 | int main(){ 24 | test1(); 25 | test2(); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/data_structures/line_container_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/line_container.h" 2 | 3 | void testAddAndGet(){ 4 | LineContainer lc; 5 | lc.add(1, -10); 6 | lc.add(-2, -30); 7 | 8 | for (int x = -100; x >= -7; x--) 9 | assert(lc.getMax(x) == (-2 * x - 30)); 10 | for (int x = -6; x <= 100; x++) 11 | assert(lc.getMax(x) == (1 * x - 10)); 12 | 13 | lc.add(0, 6); 14 | for (int x = -100; x >= -18; x--) 15 | assert(lc.getMax(x) == (-2 * x - 30)); 16 | for (int x = -18; x <= 16; x++) 17 | assert(lc.getMax(x) == (0 * x + 6)); 18 | for (int x = 16; x <= 100; x++) 19 | assert(lc.getMax(x) == (1 * x - 10)); 20 | } 21 | 22 | int main(){ 23 | testAddAndGet(); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /code/graph/floyd_warshall.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | const ll INFLL = 0x3f3f3f3f3f3f3f3f; 5 | namespace FloydWarshall{ 6 | vector> dist; 7 | int n; 8 | void init(int n1){ 9 | n = n1; 10 | dist.assign(n, vector(n, INFLL)); 11 | for(int i=0; i> solve(){ 18 | for(int k=0; k 2 | using namespace std; 3 | using ll = long long; 4 | using pll = pair; 5 | // O(N) 6 | pll bruteForce(ll n){ 7 | ll ans1 = 0, ans2 = 0; 8 | for(ll i = 1; i <= n; i++){ 9 | ans1 += n/i; 10 | ans2 += (n/i)*i; // n - (n mod i); 11 | } 12 | return pll(ans1, ans2); 13 | } 14 | ll AP(ll a1, ll an){ 15 | ll n = (an-a1+1); 16 | return ((a1+an)*n)/2LL; 17 | } 18 | // O(sqrt(N)) 19 | pll divisionTrick(ll n){ 20 | ll ans1 = 0, ans2 = 0; 21 | for(ll l = 1, r; l <= n; l = r + 1) { 22 | r = n / (n / l); 23 | // n / i has the same value for l <= i <= r 24 | ans1 += (n/l)*(r-l+1); 25 | ans2 += (n/l)*AP(l, r); 26 | } 27 | return pll(ans1, ans2); 28 | } 29 | -------------------------------------------------------------------------------- /test/miscellaneous/counting_inversions_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/counting_inversions.h" 2 | void test1(){ 3 | int T = 5; 4 | srand(2020); 5 | while(T--){ 6 | int n = 1000; 7 | vector v(n); 8 | for(int i=0; i v[j]); 14 | assert(ans == ci(v)); 15 | } 16 | } 17 | void test2(){ 18 | assert(true); // AC: https://www.spoj.com/submit/INVCNT/ 19 | assert(true); // AC: https://neps.academy/problem/63 20 | assert(true); // AC: https://cses.fi/problemset/task/1162/ 21 | } 22 | int main() { 23 | test1(); 24 | test2(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /test/graph/centroid_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/centroid.h" 2 | 3 | void test1(){ 4 | Centroid::init(4); 5 | Centroid::addEdge(0, 1); 6 | Centroid::addEdge(1, 2); 7 | Centroid::addEdge(2, 3); 8 | auto p = Centroid::findCentroid(); 9 | if(p.first > p.second) 10 | swap(p.first, p.second); 11 | assert(p == pii(1, 2)); 12 | } 13 | 14 | void test2(){ 15 | Centroid::init(7); 16 | Centroid::addEdge(0, 2); 17 | Centroid::addEdge(1, 2); 18 | Centroid::addEdge(2, 3); 19 | Centroid::addEdge(3, 4); 20 | Centroid::addEdge(4, 5); 21 | Centroid::addEdge(4, 6); 22 | auto p = Centroid::findCentroid(); 23 | assert(p == pii(3, 3)); 24 | } 25 | 26 | int main(){ 27 | test1(); 28 | test2(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /code/miscellaneous/parallel_binary_search.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int MAXN = 100010; 4 | int ans[MAXN]; 5 | bool test(int x); 6 | void add(int k); 7 | void remove(int k); 8 | void solve(int i, int j, vector &v){ 9 | if(v.empty()) 10 | return; 11 | if(i == j){ 12 | for(int x: v) 13 | ans[x] = i; 14 | return; 15 | } 16 | int mid = (i+j)/2; 17 | for(int k=i; k<=mid; k++) 18 | add(k); 19 | vector left, right; 20 | for(int x: v){ 21 | if(test(x)) 22 | left.push_back(x); 23 | else 24 | right.push_back(x); 25 | } 26 | solve(mid+1, j, right); 27 | for(int k=mid; k>=i; k--) 28 | remove(k); // Or roolback(); 29 | solve(i, mid, left); 30 | } 31 | -------------------------------------------------------------------------------- /test/math/karatsuba_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/karatsuba.h" 2 | typedef long long ll; 3 | vector brute(vector a, vector b){ 4 | int n = a.size(), m = b.size(); 5 | vector ans(n + m, 0); 6 | for (int i = 0; i < n; i++) 7 | for (int j = 0; j < m; j++) 8 | ans[i+j] += a[i] * b[j]; 9 | return ans; 10 | } 11 | void test1(){ 12 | srand(98); 13 | int n = 2048; 14 | for(int t=1; t<=5; t++){ 15 | vector a(n), b(n); 16 | for(int i=0; i ans.size() and t.find(s.substr(i, j-i+1)) != -1) 8 | ans = s.substr(i, j-i+1); 9 | } 10 | } 11 | return ans; 12 | } 13 | void test(){ 14 | srand(time(0)); 15 | int n = 500; 16 | string s(n, 0), t(n, 0); 17 | for (int i = 0; i < n; i++){ 18 | s[i] = 'a' + rand() % 26; 19 | t[i] = 'a' + rand() % 26; 20 | } 21 | SuffixAutomaton sa(s); 22 | assert(sa.lcs(t) == brute(t, s)); 23 | } 24 | int main(){ 25 | for(int i=0; i<10; i++) 26 | test(); 27 | return 0; 28 | } -------------------------------------------------------------------------------- /code/math/determinant.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long double ld; 4 | const ld EPS = 1e-9; 5 | ld determinant(vector> a) { 6 | int n = a.size(); 7 | ld det = 1; 8 | for(int i=0; i abs (a[b][i])) 12 | b = j; 13 | if(abs(a[b][i]) < EPS) 14 | return 0; 15 | swap(a[i], a[b]); 16 | if(i != b) 17 | det = -det; 18 | det *= a[i][i]; 19 | for(int j=i+1; j EPS) 23 | for(int k=i+1; k v(n); 7 | for(int i=0; i st; 12 | for(int j=i; j v1, v2; 10 | v1 = factor(12345); 11 | sort(v1.begin(), v1.end()); 12 | v2 = {3ULL, 5ULL, 823ULL}; 13 | assert(v1 == v2); 14 | 15 | v1 = factor(12345678911); 16 | sort(v1.begin(), v1.end()); 17 | v2 = {3643ULL, 3388877ULL}; 18 | assert(v1 == v2); 19 | 20 | } 21 | int main(){ 22 | testMillerRabin(); 23 | testFactor(); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /code/miscellaneous/lis.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | vector lis(vector &v){ 4 | vector st, ans; 5 | vector pos(v.size()+1), dad(v.size()+1); 6 | for(int i=0; i < (int)v.size(); i++){ 7 | auto it = lower_bound(st.begin(), st.end(), v[i]); // Do not accept repeated values 8 | //auto it = upper_bound(st.begin(), st.end(), v[i]); //Accept repeated values 9 | int p = it-st.begin(); 10 | if(it==st.end()) 11 | st.push_back(v[i]); 12 | else 13 | *it = v[i]; 14 | pos[p] = i; 15 | dad[i] = (p==0)? -1 : pos[p-1]; 16 | } 17 | int p = pos[st.size() - 1]; 18 | while(p >= 0){ 19 | ans.push_back(v[p]); 20 | p=dad[p]; 21 | } 22 | reverse(ans.begin(), ans.end()); 23 | return ans; 24 | } 25 | -------------------------------------------------------------------------------- /code/data_structures/distinct_values_in_range.h: -------------------------------------------------------------------------------- 1 | #include "segment_tree_persistent.h" 2 | namespace DistinctValues{ 3 | const int MAXN = 200010; 4 | int v0[MAXN], tmp[MAXN]; 5 | vector upd[MAXN]; 6 | void init(vector v){ 7 | int n = v.size(); 8 | map last; 9 | for(int i=0; i 2 | using namespace std; 3 | class DinamicMedian{ 4 | typedef int t_median; 5 | private: 6 | priority_queue mn; 7 | priority_queue, greater> mx; 8 | public: 9 | double median(){ 10 | if (mn.size() > mx.size()) 11 | return mn.top(); 12 | else 13 | return (mn.top() + mx.top()) / 2.0; 14 | } 15 | void push(t_median x){ 16 | if (mn.size() <= mx.size()) 17 | mn.push(x); 18 | else 19 | mx.push(x); 20 | if ((!mx.empty()) and (!mn.empty())){ 21 | while (mn.top() > mx.top()){ 22 | t_median a = mx.top(); 23 | mx.pop(); 24 | t_median b = mn.top(); 25 | mn.pop(); 26 | mx.push(b); 27 | mn.push(a); 28 | } 29 | } 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /code/miscellaneous/counting_inversions.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | const int INF = 0x3f3f3f3f; 5 | // Counting Inversions: O(N*log(N)) 6 | ll ci(vector &v){ 7 | int n = v.size(); 8 | ll inv = 0LL; 9 | if(n==1) 10 | return 0; 11 | vector u1, u2; 12 | for(int i=0; i < n/2; i++) 13 | u1.push_back(v[i]); 14 | for(int i=n/2; i < n; i++) 15 | u2.push_back(v[i]); 16 | inv += ci(u1); 17 | inv += ci(u2); 18 | u1.push_back(INF); 19 | u2.push_back(INF); 20 | int ini1=0, ini2=0; 21 | for(int i=0; i < n; i++){ 22 | if(u1[ini1] <= u2[ini2]){ 23 | v[i] = u1[ini1++]; 24 | }else{ 25 | v[i] = u2[ini2++]; 26 | inv += u1.size() - ini1 - 1; 27 | } 28 | } 29 | return inv; 30 | } -------------------------------------------------------------------------------- /code/miscellaneous/identify_pattern.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef pair pii; 4 | // Return the pattern of vector in O(N): pair 5 | pii identifyPattern(vector v){ 6 | int n = v.size(); 7 | reverse(v.begin(), v.end()); 8 | vector pi(n); 9 | for (int i = 1; i < n; i++) { 10 | int j = pi[i-1]; 11 | while (j > 0 and v[i] != v[j]) 12 | j = pi[j-1]; 13 | if (v[i] == v[j]) 14 | j++; 15 | pi[i] = j; 16 | } 17 | tuple ans(n, 1, n-1); 18 | for(int i=1; i<=n; i++){ 19 | int p = i - pi[i-1]; 20 | if(p == 0) 21 | continue; 22 | int idx = n-i; 23 | ans = min(ans, {idx+p, p, idx}); 24 | } 25 | auto [sum, p, idx] = ans; 26 | return pii(idx, p); 27 | } -------------------------------------------------------------------------------- /code/miscellaneous/sprague_grundy.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int MAXN = 1010; 4 | int version; 5 | int used[MAXN]; 6 | int mex() { 7 | for(int i=0; ; ++i) 8 | if(used[i] != version) 9 | return i; 10 | } 11 | int g[MAXN]; 12 | // Can remove 1, 2 and 3 13 | void grundy(){ 14 | //Base case depends on the problem 15 | g[0] = 0; 16 | g[1] = 1; 17 | g[2] = 2; 18 | //Inductive case 19 | for(int i=3; i v){ 28 | grundy(); 29 | int ans = 0; 30 | for(int x: v) 31 | ans ^= g[x]; 32 | return ((ans != 0) ? "First" : "Second"); 33 | } 34 | -------------------------------------------------------------------------------- /test/geometry/circles_to_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/circles_to_tree.h" 2 | 3 | void testCirclesToTree(){ 4 | vector vc; 5 | vc.emplace_back(0, 0, 100, 0); 6 | vc.emplace_back(0, 50, 20, 1); 7 | vc.emplace_back(0, -50, 20, 2); 8 | vc.emplace_back(0, 0, 80, 3); 9 | vc.emplace_back(0, 0, 2, 4); 10 | vc.emplace_back(0, 50, 25, 5); 11 | int n = 6; 12 | auto adj = CirclesToTree::solve(vc); 13 | vector> adj2(n, vector()); 14 | adj2[0].push_back(3); 15 | adj2[3].push_back(2); 16 | adj2[3].push_back(4); 17 | adj2[3].push_back(5); 18 | adj2[5].push_back(1); 19 | for(int i=0; i 2 | using namespace std; 3 | struct RollbackUF { 4 | vector e; 5 | vector> st; 6 | RollbackUF(int n) : e(n, -1) {} 7 | int size(int x) { return -e[find(x)]; } 8 | int find(int x) { return e[x] < 0 ? x : find(e[x]); } 9 | int time() { return st.size(); } 10 | void rollback(int t) { 11 | while (st.size() > t){ 12 | auto [a1, v1, a2, v2] = st.back(); 13 | e[a1] = v1; e[a2] = v2; 14 | st.pop_back(); 15 | } 16 | } 17 | bool unite(int a, int b) { 18 | a = find(a), b = find(b); 19 | if (a == b) return false; 20 | if (e[a] > e[b]) swap(a, b); 21 | st.push_back({a, e[a], b, e[b]}); 22 | e[a] += e[b]; e[b] = a; 23 | return true; 24 | } 25 | }; -------------------------------------------------------------------------------- /code/dynamic_programming/knuth_optimization.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | const int MAXN = 1009; 5 | const ll INFLL = 0x3f3f3f3f3f3f3f3f; 6 | ll C(int a, int b); 7 | ll dp[MAXN][MAXN]; 8 | int opt[MAXN][MAXN]; 9 | ll knuth(int n){ 10 | for (int i = 0; i < n; i++){ 11 | dp[i][i] = 0; 12 | opt[i][i] = i; 13 | } 14 | for (int s = 1; s < n; s++){ 15 | for (int i = 0, j; (i + s) < n; i++){ 16 | j = i + s; 17 | dp[i][j] = INFLL; 18 | for (int k = opt[i][j - 1]; k < min(j, opt[i + 1][j] + 1); k++){ 19 | ll cur = dp[i][k] + dp[k + 1][j] + C(i, j); 20 | if (dp[i][j] > cur){ 21 | dp[i][j] = cur; 22 | opt[i][j] = k; 23 | } 24 | } 25 | } 26 | } 27 | return dp[0][n - 1]; 28 | } -------------------------------------------------------------------------------- /test/math/basic_math_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/basic_math.h" 2 | void testFastPow(){ 3 | for (ll mod = 2; mod <= 100; mod++){ 4 | for (ll base = 0; base <= 100; base++){ 5 | ll ans = 1; 6 | for (ll exp = 1; exp <= 100; exp++){ 7 | ans = (ans * base) % mod; 8 | assert(ans == fastPow(base, exp, mod)); 9 | } 10 | } 11 | } 12 | } 13 | void testFloorSum(){ 14 | for(int a=0; a<50; a++){ 15 | for(int b=0; b<50; b++){ 16 | for(int m=max(a, b)+1; m <= 50; m++){ 17 | ll ans = 0; 18 | for(int n = 1; n<=50; n++){ 19 | ans += (a*(n-1)+b)/m; 20 | assert(ans == floor_sum(n, m, a, b)); 21 | } 22 | } 23 | } 24 | } 25 | } 26 | int main(){ 27 | testFastPow(); 28 | testFloorSum(); 29 | return 0; 30 | } -------------------------------------------------------------------------------- /code/graph/topological_sort.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | namespace TopologicalSort{ 4 | typedef pair pii; 5 | vector> adj; 6 | vector visited; 7 | vector vAns; 8 | void dfs(int u){ 9 | visited[u] = true; 10 | for (int to : adj[u]){ 11 | if (!visited[to]) 12 | dfs(to); 13 | } 14 | vAns.push_back(u); 15 | } 16 | vector order(int n, vector &edges){ 17 | adj.assign(n, vector()); 18 | for (pii p : edges) 19 | adj[p.first].push_back(p.second); 20 | visited.assign(n, false); 21 | vAns.clear(); 22 | for (int i = 0; i < n; i++){ 23 | if (!visited[i]) 24 | dfs(i); 25 | } 26 | reverse(vAns.begin(), vAns.end()); 27 | return vAns; 28 | } 29 | }; // namespace TopologicalSort -------------------------------------------------------------------------------- /test/strings/trie_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/trie.h" 2 | 3 | void test(){ 4 | Trie t; 5 | t.add("paulo"); 6 | t.add("paula"); 7 | assert(t.countPre("paulo") == 1); 8 | assert(t.countPre("paula") == 1); 9 | assert(t.countPre("paul") == 2); 10 | assert(t.countStr("paulo") == 1); 11 | assert(t.countStr("paula") == 1); 12 | assert(t.countStr("paul") == 0); 13 | 14 | assert(t.remove("paul") == false); 15 | assert(t.remove("paulo") == true); 16 | assert(t.remove("paulo") == false); 17 | 18 | assert(t.countPre("paulo") == 0); 19 | assert(t.countPre("paula") == 1); 20 | assert(t.countPre("paul") == 1); 21 | assert(t.countStr("paulo") == 0); 22 | assert(t.countStr("paula") == 1); 23 | assert(t.countStr("paul") == 0); 24 | } 25 | 26 | int main() { 27 | test(); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/data_structures/bit_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/bit.h" 2 | 3 | void testAddAndGet(){ 4 | Bit bit(10); 5 | bit.add(1, 2); 6 | bit.add(4, 3); 7 | bit.add(7, 5); 8 | 9 | assert(bit.get(1, 1) == 2); 10 | assert(bit.get(4, 4) == 3); 11 | assert(bit.get(7, 7) == 5); 12 | 13 | assert(bit.get(1) == 2); 14 | assert(bit.get(4) == 5); 15 | assert(bit.get(7) == 10); 16 | } 17 | 18 | void testGetPosition(){ 19 | Bit bit(10); 20 | bit.add(1, 2); 21 | bit.add(4, 3); 22 | bit.add(7, 5); 23 | 24 | assert(bit.get(1) == 2); 25 | assert(bit.get(4) == 5); 26 | assert(bit.get(7) == 10); 27 | 28 | assert(bit.lower_bound(2) == 1); 29 | assert(bit.lower_bound(5) == 4); 30 | assert(bit.lower_bound(10) == 7); 31 | } 32 | 33 | int main(){ 34 | testAddAndGet(); 35 | testGetPosition(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /code/graph/flow_with_demand.h: -------------------------------------------------------------------------------- 1 | #include "dinic.h" 2 | using namespace std; 3 | template 4 | struct MaxFlowEdgeDemands{ 5 | Dinic mf; 6 | vector ind, outd; 7 | flow_t D; 8 | int n; 9 | MaxFlowEdgeDemands(int n) : n(n){ 10 | D = 0; 11 | mf.init(n + 2); 12 | ind.assign(n, 0); 13 | outd.assign(n, 0); 14 | } 15 | void addEdge(int a, int b, flow_t cap, flow_t demands){ 16 | mf.addEdge(a, b, cap - demands); 17 | D += demands; 18 | ind[b] += demands; 19 | outd[a] += demands; 20 | } 21 | bool solve(int s, int t){ 22 | mf.addEdge(t, s, numeric_limits::max()); 23 | for (int i = 0; i < n; i++){ 24 | if (ind[i]) mf.addEdge(n, i, ind[i]); 25 | if (outd[i]) mf.addEdge(i, n + 1, outd[i]); 26 | } 27 | return mf.maxFlow(n, n + 1) == D; 28 | } 29 | }; -------------------------------------------------------------------------------- /test/data_structures/rmq_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/rmq.h" 2 | 3 | const int MAXX = 1000000000; 4 | const int MAXN = 1000; 5 | vector v; 6 | 7 | int randWithNeg(){ 8 | if (rand() % 2) 9 | return (rand() % MAXX); 10 | else 11 | return -(rand() % MAXX); 12 | } 13 | 14 | int rangeMin(int a, int b){ 15 | int ans = v[a]; 16 | for (int i = a + 1; i <= b; i++) 17 | ans = min(ans, v[i]); 18 | return ans; 19 | } 20 | 21 | void testQuery(){ 22 | srand(98); 23 | v.resize(MAXN); 24 | for (int i = 0; i < MAXN; i++){ 25 | v[i] = randWithNeg(); 26 | } 27 | 28 | RMQ rmq(v); 29 | for (int i = 0; i < MAXN; i++){ 30 | for (int j = i; j < MAXN; j++){ 31 | assert(rmq.queryMin(i, j) == rangeMin(i, j)); 32 | } 33 | } 34 | } 35 | 36 | int main(){ 37 | testQuery(); 38 | return 0; 39 | } -------------------------------------------------------------------------------- /test/graph/minimum_cost_maximum_flow_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/minimum_cost_maximum_flow.h" 2 | typedef pair pii; 3 | void test1(){ 4 | MCMF mcmf(10); 5 | for (int i = 1; i <= 4; i++) 6 | mcmf.addEdge(0, i, 1, 0); 7 | 8 | mcmf.addEdge(1, 5, 1, 2); 9 | mcmf.addEdge(2, 5, 1, 0); 10 | mcmf.addEdge(2, 6, 1, 4); 11 | mcmf.addEdge(2, 7, 1, 6); 12 | mcmf.addEdge(3, 6, 1, 1); 13 | mcmf.addEdge(3, 7, 1, 1); 14 | mcmf.addEdge(3, 8, 1, 1); 15 | mcmf.addEdge(4, 7, 1, 10); 16 | 17 | for (int i = 5; i <= 8; i++) 18 | mcmf.addEdge(i, 9, 1, 0); 19 | auto ans = mcmf.solve(0, 9); 20 | assert(ans.first == 4); 21 | assert(ans.second == 17); 22 | } 23 | void test2(){ 24 | assert(true); // AC: https://cses.fi/problemset/task/2121/ 25 | } 26 | int main(){ 27 | test1(); 28 | test2(); 29 | return 0; 30 | } -------------------------------------------------------------------------------- /test/math/matrix_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/matrix.h" 2 | int nthFib(int n){ 3 | if(n < 1) 4 | return 0; 5 | Matrix base({{1, 1, 1}, {0, 1, 1}, {0, 1, 0}}); 6 | base = fastPow(base, n-1); 7 | return modSum(base[1][0], base[1][1]); 8 | } 9 | int sumFib(int n){ 10 | if(n < 1) 11 | return 0; 12 | Matrix base({{1, 1, 1}, {0, 1, 1}, {0, 1, 0}}); 13 | base = fastPow(base, n-1); 14 | return modSum(base[0][0], base[0][1]); 15 | } 16 | const int MAXN = 10010; 17 | int fib[MAXN]; 18 | int sum[MAXN]; 19 | void test(){ 20 | fib[0] = sum[0] = 0; 21 | fib[1] = sum[1] = 1; 22 | for(int i=2; i 2 | #include "extended_euclidean.h" 3 | using namespace std; 4 | typedef long long ll; 5 | namespace CRT{ 6 | inline ll normalize(ll x, ll mod){ 7 | x %= mod; 8 | if (x < 0) 9 | x += mod; 10 | return x; 11 | } 12 | ll solve(vector a, vector m){ 13 | int n = a.size(); 14 | for (int i = 0; i < n; i++) 15 | normalize(a[i], m[i]); 16 | ll ans = a[0]; 17 | ll lcm1 = m[0]; 18 | for (int i = 1; i < n; i++){ 19 | ll x, y; 20 | ll g = extGcd(lcm1, m[i], x, y); 21 | if ((a[i] - ans) % g != 0) 22 | return -1; 23 | ans = normalize(ans + ((((a[i] - ans) / g) * x) % (m[i] / g)) * lcm1, (lcm1 / g) * m[i]); 24 | lcm1 = (lcm1 / g) * m[i]; //lcm(lcm1, m[i]); 25 | } 26 | return ans; 27 | } 28 | } // namespace CRT -------------------------------------------------------------------------------- /code/data_structures/union_find_persistent.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | namespace UnionFind{ 4 | const int MAXN = 200010; 5 | int n, p[MAXN], sz[MAXN], ti[MAXN], T; 6 | void build(int n0) { 7 | T = -1, n = n0; 8 | for (int i = 0; i < n; i++) { 9 | p[i] = i; 10 | sz[i] = 1; 11 | ti[i] = -1; 12 | } 13 | } 14 | int find(int k, int t) { 15 | if (p[k] == k or ti[k] > t) return k; 16 | return find(p[k], t); 17 | } 18 | bool join(int a, int b, int t) { 19 | assert(T <= t); 20 | a = find(a, t); b = find(b, t); 21 | if (a == b) return false; 22 | if (sz[a] > sz[b]) swap(a, b); 23 | sz[b] += sz[a]; 24 | p[a] = b; 25 | ti[a] = t; 26 | T = t; 27 | return true; 28 | } 29 | bool isSame(int a, int b, int t){ 30 | return find(a, t) == find(b, t); 31 | } 32 | } -------------------------------------------------------------------------------- /code/miscellaneous/automaton.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int K = 26; 4 | struct Automaton{ 5 | int n; 6 | vector> to; 7 | vector accept; 8 | Automaton(int sz, bool acceptAll=true){ 9 | to.assign(sz, {0}); 10 | accept.assign(sz, acceptAll); 11 | n = sz; 12 | } 13 | }; 14 | const int INTERSECT=0, UNION=1; 15 | Automaton join(Automaton a, Automaton b, int op=INTERSECT){ 16 | Automaton ret(a.n * b.n); 17 | for(int i=0; i> n >> q; 5 | for(int i=0; i> x; 8 | lct::makeTree(i, x); 9 | } 10 | for(int i=0; i> a >> b; 13 | lct::link(a, b); 14 | } 15 | while(q--){ 16 | int op; 17 | cin >> op; 18 | if(op == 0){ 19 | int u, v, w, x; 20 | cin >> u >> v >> w >> x; 21 | lct::cut(u, v); 22 | lct::link(w, x); 23 | }else if(op == 1){ 24 | int p, x; 25 | cin >> p >> x; 26 | lct::update(p, p, x); 27 | }else{ 28 | int u, v; 29 | cin >> u >> v; 30 | cout << lct::query(u, v) << endl; 31 | } 32 | } 33 | } 34 | int main() { 35 | //test1(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /code/data_structures/union_find.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class UnionFind{ 4 | private: 5 | vector p, w, sz; 6 | public: 7 | UnionFind(int n){ 8 | w.resize(n + 1, 1); 9 | sz.resize(n + 1, 1); 10 | p.resize(n + 1); 11 | for (int i = 0; i <= n; i++) 12 | p[i] = i; 13 | } 14 | int find(int x){ 15 | if (p[x] == x) 16 | return x; 17 | return p[x] = find(p[x]); 18 | } 19 | bool join(int x, int y){ 20 | x = find(x); 21 | y = find(y); 22 | if (x == y) 23 | return false; 24 | if (w[x] > w[y]) 25 | swap(x, y); 26 | p[x] = y; 27 | sz[y] += sz[x]; 28 | if (w[x] == w[y]) 29 | w[y]++; 30 | return true; 31 | } 32 | bool isSame(int x, int y){ 33 | return find(x) == find(y); 34 | } 35 | int size(int x){ 36 | return sz[find(x)]; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /test/math/fraction_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/fraction.h" 2 | void testFraction(){ 3 | Fraction a, b; 4 | a = {1, 3}; 5 | b = {2, 3}; 6 | assert(a+b == Fraction(1, 1)); 7 | assert(a-b == Fraction(-1, 3)); 8 | assert(b-a == Fraction(1, 3)); 9 | assert(a*b == Fraction(2, 9)); 10 | assert(a/b == Fraction(1, 2)); 11 | 12 | a = {5, 3}; 13 | b = {3, 3}; 14 | assert(a+b == Fraction(8, 3)); 15 | assert(a-b == Fraction(2, 3)); 16 | assert(b-a == Fraction(-2, 3)); 17 | assert(a*b == Fraction(15, 9)); 18 | assert(a/b == Fraction(5, 3)); 19 | 20 | a = {5, 3}; 21 | b = {3, 2}; 22 | assert(a+b == Fraction(19, 6)); 23 | assert(a-b == Fraction(1, 6)); 24 | assert(b-a == Fraction(-1, 6)); 25 | assert(a*b == Fraction(15, 6)); 26 | assert(a/b == Fraction(10, 9)); 27 | } 28 | 29 | int main(){ 30 | testFraction(); 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /test/data_structures/distinct_values_in_range_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/distinct_values_in_range.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 1010; 4 | 5 | int randWithNeg(){ 6 | if (rand() % 2) 7 | return (rand() % MAXX); 8 | else 9 | return -(rand() % MAXX); 10 | } 11 | 12 | vector v(MAXN); 13 | 14 | void test1(){ 15 | srand(48); 16 | for (int i = 0; i < MAXN; i++){ 17 | v[i] = randWithNeg(); 18 | } 19 | DistinctValues::init(v); 20 | for (int i = 0; i < MAXN; i++){ 21 | set st; 22 | for (int j = i; j < MAXN; j++){ 23 | st.insert(v[j]); 24 | assert(DistinctValues::query(i, j) == st.size()); 25 | } 26 | } 27 | } 28 | 29 | void test2(){ 30 | assert(true); // AC: https://cses.fi/problemset/task/1734/ 31 | } 32 | 33 | int main(){ 34 | test1(); 35 | test2(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /test/data_structures/stack_query_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/stack_query.h" 2 | 3 | void testPushAndQuery(){ 4 | StackQuery sq; //Minimum 5 | sq.push(10); 6 | sq.push(1); 7 | sq.push(8); 8 | sq.push(5); 9 | 10 | assert(sq.top() == 5); 11 | assert(sq.query() == 1); 12 | assert(sq.size() == 4); 13 | sq.pop(); 14 | assert(sq.top() == 8); 15 | assert(sq.query() == 1); 16 | assert(sq.size() == 3); 17 | sq.pop(); 18 | assert(sq.top() == 1); 19 | assert(sq.query() == 1); 20 | assert(sq.size() == 2); 21 | sq.pop(); 22 | sq.push(-2); 23 | assert(sq.top() == -2); 24 | assert(sq.query() == -2); 25 | assert(sq.size() == 2); 26 | sq.pop(); 27 | assert(sq.top() == 10); 28 | assert(sq.query() == 10); 29 | assert(sq.size() == 1); 30 | sq.pop(); 31 | assert(sq.size() == 0); 32 | } 33 | 34 | int main(){ 35 | testPushAndQuery(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /test/strings/kmp_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/kmp.h" 2 | 3 | void test1(){ 4 | assert(true); // AC: https://codeforces.com/contest/808/submission/97043263 5 | assert(true); // AC: https://codeforces.com/contest/471/submission/61944132 6 | assert(true); // AC: https://codeforces.com/contest/432/submission/97050237 7 | } 8 | void test2(){ 9 | vector pi = kmp("abcabcd"); 10 | vector ans = {0,0,0,1,2,3,0}; 11 | assert(pi == ans); 12 | } 13 | void test3(){ 14 | vector pi = kmp("aabaaab"); 15 | vector ans = {0,1,0,1,2,2,3}; 16 | assert(pi == ans); 17 | } 18 | void test4(){ 19 | string s = "aabaaab"; 20 | vector prefix = prefixOccurrences(s); 21 | vector ans = {5,3,2,1,1,1,1}; 22 | assert(prefix == ans); 23 | } 24 | 25 | int main() { 26 | test1(); 27 | test2(); 28 | test3(); 29 | test4(); 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /code/math/rank_matrix.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long double ld; 4 | const ld EPS = 1e-9; 5 | int compute_rank(vector> A) { 6 | int n = A.size(); 7 | int m = A[0].size(); 8 | int rank = max(n, m); 9 | vector row_selected(n, false); 10 | for (int i = 0; i < m; ++i) { 11 | int j; 12 | for (j = 0; j < n; ++j) { 13 | if (!row_selected[j] && abs(A[j][i]) > EPS) 14 | break; 15 | } 16 | if (j == n) { 17 | rank--; 18 | } else { 19 | row_selected[j] = true; 20 | for (int p = i + 1; p < m; p++) 21 | A[j][p] /= A[j][i]; 22 | for (int k = 0; k < n; k++) { 23 | if (k != j && abs(A[k][i]) > EPS) { 24 | for (int p = i + 1; p < m; p++) 25 | A[k][p] -= A[j][p] * A[k][i]; 26 | } 27 | } 28 | } 29 | } 30 | return rank; 31 | } 32 | -------------------------------------------------------------------------------- /test/data_structures/queue_query_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/queue_query.h" 2 | 3 | void testPushAndQuery(){ 4 | QueueQuery qq; //Minimum 5 | qq.push(10); 6 | qq.push(1); 7 | qq.push(8); 8 | qq.push(5); 9 | 10 | assert(qq.front() == 10); 11 | assert(qq.query() == 1); 12 | assert(qq.size() == 4); 13 | qq.pop(); 14 | assert(qq.front() == 1); 15 | assert(qq.query() == 1); 16 | assert(qq.size() == 3); 17 | qq.pop(); 18 | assert(qq.front() == 8); 19 | assert(qq.query() == 5); 20 | assert(qq.size() == 2); 21 | qq.pop(); 22 | qq.push(-2); 23 | assert(qq.front() == 5); 24 | assert(qq.query() == -2); 25 | assert(qq.size() == 2); 26 | qq.pop(); 27 | assert(qq.front() == -2); 28 | assert(qq.query() == -2); 29 | assert(qq.size() == 1); 30 | qq.pop(); 31 | assert(qq.size() == 0); 32 | } 33 | 34 | int main(){ 35 | testPushAndQuery(); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /code/graph/find_cycle_negative.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | typedef tuple Edge; 5 | vector findNegativeCycle(vector edges, int n){ 6 | vector d(n, 0); 7 | vector p(n, -1); 8 | int last = -1; 9 | for(int i = 0; i < n; ++i){ 10 | last = -1; 11 | for(auto [u, to, w] : edges){ 12 | if(d[u] + w < d[to]){ 13 | d[to] = d[u] + w; 14 | p[to] = u; 15 | last = to; 16 | } 17 | } 18 | } 19 | if(last == -1){ 20 | return {}; 21 | }else{ 22 | for(int i = 0; i < n; i++) 23 | last = p[last]; 24 | vector cycle; 25 | for(int v = last; ; v = p[v]){ 26 | cycle.push_back(v); 27 | if(v == last && cycle.size() > 1) 28 | break; 29 | } 30 | reverse(cycle.begin(), cycle.end()); 31 | return cycle; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/miscellaneous/mo_algorithm.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int BLOCK_SIZE = 700; 4 | void remove(int idx); 5 | void add(int idx); 6 | void clearAnswer(); 7 | int getAnswer(); 8 | struct Query{ 9 | int l, r, idx; 10 | bool operator<(Query other) const{ 11 | if (l / BLOCK_SIZE != other.l / BLOCK_SIZE) 12 | return l < other.l; 13 | return (l / BLOCK_SIZE & 1) ? (r < other.r) : (r > other.r); 14 | } 15 | }; 16 | vector mo_s_algorithm(vector queries){ 17 | vector answers(queries.size()); 18 | sort(queries.begin(), queries.end()); 19 | clearAnswer(); 20 | int L = 0, R = 0; 21 | add(0); 22 | for(Query q : queries){ 23 | while(q.l < L) add(--L); 24 | while(R < q.r) add(++R); 25 | while(L < q.l) remove(L++); 26 | while(q.r < R) remove(R--); 27 | answers[q.idx] = getAnswer(); 28 | } 29 | return answers; 30 | } -------------------------------------------------------------------------------- /code/data_structures/bit2d.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class Bit2d{ 4 | private: 5 | typedef long long t_bit; 6 | vector> bit; 7 | int nBit, mBit; 8 | public: 9 | Bit2d(int n, int m){ 10 | nBit = n; 11 | mBit = m; 12 | bit.resize(nBit + 1, vector(mBit + 1, 0)); 13 | } 14 | //1-indexed 15 | t_bit get(int i, int j){ 16 | t_bit sum = 0; 17 | for (int a = i; a > 0; a -= (a & -a)) 18 | for (int b = j; b > 0; b -= (b & -b)) 19 | sum += bit[a][b]; 20 | return sum; 21 | } 22 | //1-indexed 23 | t_bit get(int a1, int b1, int a2, int b2){ 24 | return get(a2, b2) - get(a2, b1 - 1) - get(a1 - 1, b2) + get(a1 - 1, b1 - 1); 25 | } 26 | //1-indexed [i, j] 27 | void add(int i, int j, t_bit value){ 28 | for (int a = i; a <= nBit; a += (a & -a)) 29 | for (int b = j; b <= mBit; b += (b & -b)) 30 | bit[a][b] += value; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /test/data_structures/sparse_table_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/sparse_table.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 1000; 4 | int v[MAXN + 10]; 5 | 6 | int randWithNeg(){ 7 | if (rand() % 2) 8 | return (rand() % MAXX); 9 | else 10 | return -(rand() % MAXX); 11 | } 12 | 13 | int rangeMin(int a, int b){ 14 | int ans = v[a]; 15 | for (int i = a + 1; i <= b; i++) 16 | ans = min(ans, v[i]); 17 | return ans; 18 | } 19 | 20 | void testQuery(){ 21 | srand(42); 22 | for (int i = 0; i < MAXN; i++){ 23 | v[i] = randWithNeg(); 24 | } 25 | 26 | SparseTable stMin(v, v + MAXN); 27 | for (int i = 0; i < MAXN; i++){ 28 | for (int j = i; j < MAXN; j++){ 29 | assert(stMin.query(i, j) == rangeMin(i, j)); 30 | assert(stMin.queryRMQ(i, j) == rangeMin(i, j)); 31 | } 32 | } 33 | } 34 | 35 | int main(){ 36 | testQuery(); 37 | return 0; 38 | } -------------------------------------------------------------------------------- /test/graph/dijkstra_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/dijkstra.h" 2 | 3 | void test1(){ 4 | int n = 4; 5 | Dijkstra::init(n); 6 | Dijkstra::addEdge(0, 1, 1); 7 | Dijkstra::addEdge(0, 2, 3); 8 | Dijkstra::addEdge(0, 3, 9); 9 | Dijkstra::addEdge(1, 3, 2); 10 | Dijkstra::addEdge(2, 3, 2); 11 | 12 | auto d = Dijkstra::solve(0); 13 | vector ans = {0, 1, 3, 3}; 14 | assert(ans == d); 15 | } 16 | 17 | void test2(){ // AC: https://neps.academy/problem/297 18 | ios_base::sync_with_stdio(false); cin.tie(NULL); 19 | int n, m; 20 | cin >> n >> m; 21 | Dijkstra::init(n+2); 22 | for(int i=0; i> a >> b >> w; 25 | Dijkstra::addEdge(a, b, w); 26 | Dijkstra::addEdge(b, a, w); 27 | } 28 | auto d = Dijkstra::solve(0); 29 | cout << d[n+1] << endl; 30 | } 31 | int main(){ 32 | test1(); 33 | // test2(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /test/graph/mincut_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/mincut.h" 2 | 3 | void test1(){ 4 | MinCut::init(5); 5 | MinCut::addEdge(0, 1, 100); 6 | MinCut::addEdge(1, 2, 299); 7 | MinCut::addEdge(2, 4, 400); 8 | MinCut::addEdge(4, 3, 99); 9 | assert(MinCut::mincut().first == 99); 10 | } 11 | 12 | void test2(){ 13 | MinCut::init(3); 14 | MinCut::addEdge(0, 1, 10); 15 | MinCut::addEdge(1, 2, 20); 16 | MinCut::addEdge(0, 2, 40); 17 | assert(MinCut::mincut().first == 30); 18 | } 19 | 20 | void test3(){ 21 | MinCut::init(4); 22 | MinCut::addEdge(0, 1, 10); 23 | MinCut::addEdge(1, 2, 100); 24 | MinCut::addEdge(2, 3, 10); 25 | MinCut::addEdge(3, 0, 100); 26 | MinCut::addEdge(0, 2, 10); 27 | assert(MinCut::mincut().first == 30); 28 | } 29 | 30 | int main() { 31 | assert(true); // https://vjudge.net/problem/UVA-10989 32 | test1(); 33 | test2(); 34 | test3(); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /code/graph/dijkstra.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | namespace Dijkstra{ 4 | typedef long long T; 5 | typedef pair pti; 6 | vector> adj; 7 | int n; 8 | void init(int n1){ 9 | n = n1; 10 | adj.assign(n, vector()); 11 | } 12 | void addEdge(int from, int to, T w){ 13 | adj[from].emplace_back(w, to); 14 | } 15 | vector solve(int s){ 16 | vector dist(n, numeric_limits::max()); 17 | dist[s] = 0; 18 | priority_queue, greater> st; 19 | st.emplace(dist[s], s); 20 | while(!st.empty()){ 21 | auto [wu, u] = st.top(); 22 | st.pop(); 23 | if(wu > dist[u]) continue; 24 | for(auto [w, to]: adj[u]){ 25 | if(dist[u] + w < dist[to]){ 26 | dist[to] = dist[u] + w; 27 | st.emplace(dist[to], to); 28 | } 29 | } 30 | } 31 | return dist; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /code/data_structures/bit_range.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class BitRange{ 4 | private: 5 | typedef long long t_bit; 6 | vector bit1, bit2; 7 | t_bit get(vector &bit, int i){ 8 | t_bit sum = 0; 9 | for (; i > 0; i -= (i & -i)) 10 | sum += bit[i]; 11 | return sum; 12 | } 13 | void add(vector &bit, int i, t_bit value){ 14 | for (; i < (int)bit.size(); i += (i & -i)) 15 | bit[i] += value; 16 | } 17 | public: 18 | BitRange(int n){ 19 | bit1.assign(n + 1, 0); 20 | bit2.assign(n + 1, 0); 21 | } 22 | //1-indexed [i, j] 23 | void add(int i, int j, t_bit v){ 24 | add(bit1, i, v); 25 | add(bit1, j + 1, -v); 26 | add(bit2, i, v * (i - 1)); 27 | add(bit2, j + 1, -v * j); 28 | } 29 | //1-indexed 30 | t_bit get(int i){ 31 | return get(bit1, i) * i - get(bit2, i); 32 | } 33 | //1-indexed [i,j] 34 | t_bit get(int i, int j){ 35 | return get(j) - get(i - 1); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /test/graph/vertex_cover_in_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/vertex_cover_in_tree.h" 2 | 3 | void test1(){ 4 | int n = 5; 5 | for(int i=0; i tree; 3 | 4 | void testDist(){ 5 | tree.init(5); 6 | 7 | tree.addEdge(0, 1); 8 | tree.addEdge(0, 2); 9 | tree.addEdge(2, 3); 10 | tree.addEdge(2, 4); 11 | 12 | tree.build(); 13 | assert(tree.dist(0, 2) == 1); 14 | assert(tree.dist(1, 4) == 3); 15 | assert(tree.dist(0, 3) == 2); 16 | 17 | assert(true); // AC: https://cses.fi/problemset/task/1135 18 | } 19 | 20 | void testLca(){ 21 | tree.init(5); 22 | 23 | tree.addEdge(0, 1); 24 | tree.addEdge(0, 2); 25 | tree.addEdge(2, 3); 26 | tree.addEdge(2, 4); 27 | 28 | tree.build(0); 29 | assert(tree.dist(0, 1) == 0); 30 | assert(tree.dist(0, 4) == 0); 31 | assert(tree.dist(1, 2) == 0); 32 | assert(tree.dist(2, 3) == 2); 33 | assert(tree.dist(3, 4) == 2); 34 | 35 | assert(true); // AC: https://judge.yosupo.jp/problem/lca 36 | } 37 | 38 | int main(){ 39 | testDist(); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /code/math/gauss_xor.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int MAXB = 30; 4 | struct GaussXOR { 5 | int table[MAXB]; 6 | GaussXOR() { 7 | for(int i = 0; i < MAXB; i++) { 8 | table[i] = 0; 9 | } 10 | } 11 | int size() { 12 | int ans = 0; 13 | for(int i = 0; i < MAXB; i++) { 14 | if(table[i]) ans++; 15 | } 16 | return ans; 17 | } 18 | bool isComb(int x) { 19 | for(int i = MAXB-1; i >= 0; i--) { 20 | x = std::min(x, x ^ table[i]); 21 | } 22 | return x == 0; 23 | } 24 | void add(int x) { 25 | for(int i = MAXB-1; i >= 0; i--) { 26 | if((table[i] == 0) and ((x>>i) & 1)){ 27 | table[i] = x; 28 | x = 0; 29 | } else { 30 | x = std::min(x, x ^ table[i]); 31 | } 32 | } 33 | } 34 | int max(){ 35 | int ans = 0; 36 | for(int i = MAXB-1; i >= 0; i--) { 37 | ans = std::max(ans, ans ^ table[i]); 38 | } 39 | return ans; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /code/graph/centroid.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int MAXN = 500010; 4 | typedef pair pii; 5 | namespace Centroid{ 6 | vector adj[MAXN]; 7 | int sub[MAXN]; 8 | int n; 9 | void init(int n1){ 10 | n = n1; 11 | for(int i=0; i n/2) 28 | return dfsC(to, u); 29 | } 30 | for(int to : adj[u]){ 31 | if(to != p and (sub[to]*2) == n) 32 | return pii(u, to); 33 | } 34 | return pii(u, u); 35 | } 36 | pii findCentroid(){ 37 | dfsS(0, -1); 38 | return dfsC(0, -1); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/theorems_and_formulas/manhattan_distance.tex: -------------------------------------------------------------------------------- 1 | Transformation of the manhattan distance to 2 dimensions between $P_1=(x_1, y_1)$ and $P_2=(x_2, y_2)$: 2 | 3 | $ |x_1 - x_2| + |y_1 - y_2| = max(|A_1-B_1|, |A_2-B_2|)$ where $A=(x_1+y_1, x_1-y_1)$ e $B=(x_2+y_2, x_2-y_2)$ 4 | 5 | Transformation of the manhattan distance to 3 dimensions between $P_1=(x_1, y_1, z_1)$ and $P_2=(x_2, y_2, z_2)$: 6 | 7 | $ |x_1 - x_2| + |y_1 - y_2| + |z_1 - z_2| = max(|A_1-B_1|, |A_2-B_2|, |A_3-B_3|, |A_4-B_4|)$ where $A=(x_1+y_1+z_1, x_1+y_1-z_1, x_1-y_1+z_1, -x_1+y_1+z_1)$ e $B=(x_2+y_2+z_2, x_2+y_2-z_2, x_2-y_2+z_2, -x_2+y_2+z_2)$ 8 | 9 | Transformation of the manhattan distance to D dimensions between $P_1$ and $P_2$: 10 | 11 | $isSet(i, x) = 1$ if the i-th bit is setted in $x$ and 0 otherwise. 12 | 13 | $A[i] = \sum_{j=0}^{d-1}(-1)^{isSet(j, i)}P_1[j]$ 14 | 15 | $B[i] = \sum_{j=0}^{d-1}(-1)^{isSet(j, i)}P_2[j]$ 16 | 17 | $$\sum_{i = 0}^{d-1} |P_1[i] - P_2[i]| = \max_{i=0}^{2^d - 1}{|A_i - B_i|}$$ 18 | -------------------------------------------------------------------------------- /test/math/bigint_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/bigint.h" 2 | void testBigInt1(){ 3 | BigInt a("1234513244000000032132300000032"); 4 | BigInt b("1324551121513244421211111222332"); 5 | BigInt c = a+b; 6 | assert(c.to_string() == "2559064365513244453343411222364"); 7 | c = a-b; 8 | assert(c.to_string() == "-90037877513244389078811222300"); 9 | c = a*b; 10 | assert(c.to_string() == "1635175901863153601955105325768291916578212950817279159114624"); 11 | } 12 | void testBigInt2(){ 13 | BigInt a("1234513244000000032132300000032"); 14 | BigInt b("124551121"); 15 | int b1 = 124551121; 16 | BigInt c = a*b1; 17 | assert(c.to_string() == "153760008429546528002113985312285635872"); 18 | c = a/b; 19 | assert(c.to_string() == "9911699180933104826349"); 20 | c = a/b1; 21 | assert(c.to_string() == "9911699180933104826349"); 22 | c = a%b; 23 | assert(c.to_string() == "21712803"); 24 | } 25 | int main(){ 26 | testBigInt1(); 27 | testBigInt2(); 28 | return 0; 29 | } -------------------------------------------------------------------------------- /code/data_structures/bit.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class Bit{ 4 | private: 5 | typedef long long t_bit; 6 | int nBit; 7 | int nLog; 8 | vector bit; 9 | public: 10 | Bit(int n){ 11 | nBit = n; 12 | nLog = 20; 13 | bit.resize(nBit + 1, 0); 14 | } 15 | //1-indexed 16 | t_bit get(int i){ 17 | t_bit s = 0; 18 | for (; i > 0; i -= (i & -i)) 19 | s += bit[i]; 20 | return s; 21 | } 22 | //1-indexed [l, r] 23 | t_bit get(int l, int r){ 24 | return get(r) - get(l - 1); 25 | } 26 | //1-indexed 27 | void add(int i, t_bit value){ 28 | assert(i > 0); 29 | for (; i <= nBit; i += (i & -i)) 30 | bit[i] += value; 31 | } 32 | t_bit lower_bound(t_bit value){ 33 | t_bit sum = 0; 34 | int pos = 0; 35 | for (int i = nLog; i >= 0; i--){ 36 | if ((pos + (1 << i) <= nBit) and (sum + bit[pos + (1 << i)] < value)){ 37 | sum += bit[pos + (1 << i)]; 38 | pos += (1 << i); 39 | } 40 | } 41 | return pos + 1; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /test/strings/manacher_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/manacher.h" 2 | string s; 3 | bool isPalindrome(int i, int j){ 4 | while(i < j) 5 | if(s[i++] != s[j--]) 6 | return false; 7 | return true; 8 | } 9 | void test1(){ 10 | srand(2020); 11 | int n = 1000; 12 | s.resize(n); 13 | for(int i=0; i> t; 26 | auto man = manacher(t); 27 | int i = max_element(man.begin(), man.end()) - man.begin(); 28 | int p = i/2, sz = man[i]; 29 | if(i%2 == 0){ 30 | cout << s.substr(p - sz/2, sz) << endl; 31 | }else{ 32 | cout << s.substr(p - sz/2 + 1, sz) << endl; 33 | } 34 | } 35 | 36 | int main() { 37 | test1(); 38 | // test2(); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /code/geometry/general_polygon.h: -------------------------------------------------------------------------------- 1 | #include "basic_geometry.h" 2 | const int INSIDE=-1, BOUNDARY=0, OUTSIDE=1; 3 | struct GeneralPolygon{ 4 | vector vp; 5 | GeneralPolygon(vector aux){ 6 | vp = aux; 7 | } 8 | // -1 inside, 0 boundary, 1 outside 9 | int pointInPolygon(Point2d pt) { 10 | int n = vp.size(), w = 0; 11 | for(int i=0; i 0)) 24 | w += below ? 1 : -1; 25 | } 26 | } 27 | } 28 | return (w==0?1:-1); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /code/graph/bfs01.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef pair pii; 4 | const int N = 500010; 5 | const int INF = 0x3f3f3f3f; 6 | namespace BFS01{ 7 | vector adj[N]; 8 | int n; 9 | void init(int n1){ 10 | n = n1; 11 | for(int i=0; i solve(int s){ 18 | vector d(n, INF); 19 | d[s] = 0; 20 | deque q; 21 | q.push_front(s); 22 | while (!q.empty()) { 23 | int u = q.front(); 24 | q.pop_front(); 25 | for (auto edge : adj[u]) { 26 | int to = edge.first; 27 | int w = edge.second; 28 | if (d[u] + w < d[to]) { 29 | d[to] = d[u] + w; 30 | if (w == 1) 31 | q.push_back(to); 32 | else 33 | q.push_front(to); 34 | } 35 | } 36 | } 37 | return d; 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /test/data_structures/segment_tree_2d_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/segment_tree_2d.h" 2 | int mat[1010][1010]; 3 | int bruteForce(int x1, int y1, int x2, int y2){ 4 | int mx = -0x3f3f3f3f; 5 | for(int a=x1; a<=x2; a++) 6 | for(int b=y1; b<=y2; b++) 7 | mx = max(mx, mat[a][b]); 8 | return mx; 9 | } 10 | void testInsertAndQuery(){ 11 | int n = 600; 12 | int m = 565; 13 | SegTree2D seg2d(n, m); 14 | srand(2020); 15 | for(int i=0; i<1000; i++){ 16 | int x1 = rand()%n; 17 | int x2 = rand()%n; 18 | int y1 = rand()%m; 19 | int y2 = rand()%m; 20 | if(x1 > x2) 21 | swap(x1, x2); 22 | if(y1 > y2) 23 | swap(y1, y2); 24 | assert(bruteForce(x1, y1, x2, y2) == seg2d.query(x1, y1, x2, y2)); 25 | 26 | int x = rand()%n; 27 | int y = rand()%m; 28 | int newValue = rand(); 29 | seg2d.update(x, y, newValue); 30 | mat[x][y] = newValue; 31 | } 32 | } 33 | 34 | int main(){ 35 | testInsertAndQuery(); 36 | return 0; 37 | } -------------------------------------------------------------------------------- /code/graph/checking_bipartiteness_online.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef pair pii; 4 | const int N = 500010; 5 | pii parent[N]; 6 | int rk[N]; 7 | int bipartite[N]; 8 | void make_set(int v) { 9 | parent[v] = pii(v, 0); 10 | rk[v] = 0; 11 | bipartite[v] = true; 12 | } 13 | pii find_set(int v) { 14 | if (v != parent[v].first) { 15 | int parity = parent[v].second; 16 | parent[v] = find_set(parent[v].first); 17 | parent[v].second ^= parity; 18 | } 19 | return parent[v]; 20 | } 21 | void add_edge(int a, int b) { 22 | int x, y; 23 | tie(a, x) = find_set(a); 24 | tie(b, y) = find_set(b); 25 | if (a == b) { 26 | if (x == y) 27 | bipartite[a] = false; 28 | }else{ 29 | if (rk[a] < rk[b]) 30 | swap (a, b); 31 | parent[b] = pii(a, x^y^1); 32 | bipartite[a] &= bipartite[b]; 33 | if (rk[a] == rk[b]) 34 | ++rk[a]; 35 | } 36 | } 37 | bool is_bipartite(int v) { 38 | return bipartite[find_set(v).first]; 39 | } -------------------------------------------------------------------------------- /test/data_structures/merge_sort_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/merge_sort_tree.h" 2 | 3 | const int MAXN = 5010; 4 | int v[MAXN]; 5 | int bruteForceEq(int l, int r, int k){ 6 | int ans = 0; 7 | for(int i=l; i<=r; i++) 8 | ans += (v[i]==k); 9 | return ans; 10 | } 11 | int bruteForceLt(int l, int r, int k){ 12 | int ans = 0; 13 | for(int i=l; i<=r; i++) 14 | ans += (v[i] r) 27 | swap(l, r); 28 | assert(mst.lt(l, r, k) == bruteForceLt(l, r, k)); 29 | assert(mst.eq(l, r, k) == bruteForceEq(l, r, k)); 30 | } 31 | assert(true);// AC: https://www.spoj.com/problems/MKTHNUM/ 32 | } 33 | int main() { 34 | for(int i=0; i<5; i++) 35 | test1(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /test/strings/z_function_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/z_function.h" 2 | 3 | string s; 4 | int bruteForceZ(int j){ 5 | int i = 0, n = s.size(); 6 | while((j < n) and (s[i] == s[j])){ 7 | i++; 8 | j++; 9 | } 10 | return i; 11 | } 12 | void test1(){ 13 | srand(2020); 14 | int n = 1000; 15 | s.resize(n); 16 | for(int i=0; i> t; 27 | auto z = z_function(t); 28 | int n = t.size(); 29 | vector ans; 30 | for(int i=1; i 2 | using namespace std; 3 | typedef long long ll; 4 | // Largest Rectangular Area in a Histogram 5 | ll histogram(vector v){ 6 | int n = v.size(); 7 | v.push_back(0); 8 | ll ans = 0; 9 | stack st; 10 | for(int i = 0; i<=n; i++){ 11 | while(st.size() && v[st.top()] >= v[i]){ 12 | int idx = st.top(); st.pop(); 13 | int L = st.size() ? st.top() : -1; 14 | ans = max(ans, (i-L-1) * (ll)v[idx]); 15 | } 16 | st.push(i); 17 | } 18 | return ans; 19 | } 20 | 21 | // Largest Rectangular Area formed only by 1 22 | int maxArea1(vector> mat){ 23 | int n = mat.size(); 24 | if(n == 0) 25 | return 0; 26 | int m = mat[0].size(); 27 | vector v(m, 0); 28 | int ans = 0; 29 | for(int i=0; i v; 4 | v.emplace_back(0, 0); 5 | v.emplace_back(10, 0); 6 | v.emplace_back(0, 10); 7 | auto ans1 = convex_hull(v); 8 | vector ans2; 9 | ans2.emplace_back(0, 0); 10 | ans2.emplace_back(10, 0); 11 | ans2.emplace_back(0, 10); 12 | sort(ans1.begin(), ans1.end()); 13 | sort(ans2.begin(), ans2.end()); 14 | assert(ans1 == ans2); 15 | } 16 | void test2(){ 17 | vector v; 18 | v.emplace_back(41, -6); 19 | v.emplace_back(-24, -74); 20 | v.emplace_back(-51, -6); 21 | v.emplace_back(73, 17); 22 | v.emplace_back(-30, -34); 23 | auto ans1 = convex_hull(v); 24 | vector ans2; 25 | ans2.emplace_back(-24, -74); 26 | ans2.emplace_back(73, 17); 27 | ans2.emplace_back(-51, -6); 28 | sort(ans1.begin(), ans1.end()); 29 | sort(ans2.begin(), ans2.end()); 30 | assert(ans1 == ans2); 31 | } 32 | int main(){ 33 | test1(); 34 | test2(); 35 | return 0; 36 | } -------------------------------------------------------------------------------- /test/dynamic_programming/knuth_optimization_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/dynamic_programming/knuth_optimization.h" 2 | ll v[MAXN]; 3 | ll sum[MAXN]; 4 | ll C(int a, int b){ 5 | return sum[b]-((a>0)?sum[a-1]:0); 6 | } 7 | ll bruteforce(int i, int j){ 8 | if(i > j) 9 | return 0; 10 | if (i == j) 11 | return 0; 12 | ll ans = INFLL; 13 | for(int k=i; k 2 | using namespace std; 3 | typedef long long ll; 4 | // Largest Sum Contiguous Subarray: O(N) 5 | ll kadane(vector &v){ 6 | ll ans = 0, bigger = 0; 7 | for(int i=0; i < (int)v.size(); i++){ 8 | bigger = max(0LL, bigger + v[i]); 9 | ans = max(ans, bigger); 10 | } 11 | return ans; 12 | } 13 | // Largest Sum Submatrix: O(N^3) 14 | ll kadane2d(vector> &mat){ 15 | if(mat.size() == 0) return 0; 16 | int n = mat.size(), m = mat[0].size(); 17 | ll ans = 0; 18 | vector v(m); 19 | for(int a=0; a v){ 30 | ll ans1 = kadane(v); 31 | ll sum = 0; 32 | for(int i=0; i < (int)v.size(); i++){ 33 | sum += v[i]; 34 | v[i] = -v[i]; 35 | } 36 | return max(ans1, sum + kadane(v)); 37 | } -------------------------------------------------------------------------------- /test/miscellaneous/mo_algorithm_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/mo_algorithm.h" 2 | int ans; 3 | vector v; 4 | void add(int i){ 5 | ans += v[i]; 6 | } 7 | void remove(int i){ 8 | ans -= v[i]; 9 | } 10 | int getAnswer(){ 11 | return ans; 12 | } 13 | void clearAnswer(){ 14 | ans = 0; 15 | } 16 | 17 | int brute(int i, int j){ 18 | int sum = 0; 19 | for (int k = i; k <= j; k++) 20 | sum += v[k]; 21 | return sum; 22 | } 23 | void testMo(){ 24 | srand(time(0)); 25 | int n = 1000; 26 | v.resize(n); 27 | for (int i = 0; i < n; i++) 28 | v[i] = rand() % 100000; 29 | vector q(n); 30 | for (int i = 0; i < n; i++){ 31 | q[i].idx = i; 32 | q[i].l = rand() % n; 33 | q[i].r = rand() % n; 34 | if (q[i].l > q[i].r) 35 | swap(q[i].l, q[i].r); 36 | } 37 | vector ans = mo_s_algorithm(q); 38 | for (int i = 0; i < n; i++) 39 | assert(ans[i] == brute(q[i].l, q[i].r)); 40 | } 41 | int main(){ 42 | for(int i=0; i<10; i++) 43 | testMo(); 44 | 45 | return 0; 46 | } -------------------------------------------------------------------------------- /code/data_structures/permutation.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using ll = long long; 4 | mt19937_64 rng((int) std::chrono::steady_clock::now().time_since_epoch().count()); 5 | namespace Permutation{ 6 | const int MAXN = 500010; 7 | ll mp[MAXN], sumXor[MAXN], p[MAXN+1], inv[MAXN]; 8 | void init(vector v){ 9 | sumXor[0] = inv[0] = p[0] = 0; 10 | for(int i=0; i= MAXN){ 16 | inv[i+1] = 1 + inv[i]; 17 | sumXor[i+1] = sumXor[i]; 18 | }else{ 19 | inv[i+1] = inv[i]; 20 | sumXor[i+1] = sumXor[i] ^ mp[v[i]]; 21 | } 22 | } 23 | } 24 | // Verify if {v[l], v[l+1], ..., v[r]} is {0, 1, ... , r-l+1} 25 | // 0-indexed; 26 | bool isPermutation(int l, int r){ 27 | l++, r++; 28 | if(inv[r] - inv[l-1] > 0) 29 | return false; 30 | return p[r-l+1] == (sumXor[r] ^ sumXor[l-1]); 31 | } 32 | }; -------------------------------------------------------------------------------- /code/math/matrix.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "modular.h" 3 | using namespace std; 4 | const int D = 3; 5 | struct Matrix{ 6 | int m[D][D]; 7 | Matrix(bool identify = false){ 8 | memset(m, 0, sizeof(m)); 9 | for (int i = 0; i < D; i++) 10 | m[i][i] = identify; 11 | } 12 | Matrix(vector> mat){ 13 | for(int i=0; i>=1; 39 | } 40 | return ans; 41 | } -------------------------------------------------------------------------------- /code/dynamic_programming/dc_optimization.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int C(int i, int j); 4 | const int MAXN = 100010; 5 | const int MAXK = 110; 6 | const int INF = 0x3f3f3f3f; 7 | int dp[MAXN][MAXK]; 8 | void calculateDP(int l, int r, int k, int opt_l, int opt_r){ 9 | if (l > r) 10 | return; 11 | int mid = (l + r) >> 1; 12 | int ans = -INF, opt = mid; 13 | // int ans = dp[mid][k-1], opt=mid; //If you accept empty subsegment 14 | for (int i = opt_l; i <= min(opt_r, mid - 1); i++){ 15 | if (ans < dp[i][k - 1] + C(i + 1, mid)){ 16 | opt = i; 17 | ans = dp[i][k - 1] + C(i + 1, mid); 18 | } 19 | } 20 | dp[mid][k] = ans; 21 | calculateDP(l, mid - 1, k, opt_l, opt); 22 | calculateDP(mid + 1, r, k, opt, opt_r); 23 | } 24 | int solve(int n, int k){ 25 | for (int i = 0; i <= n; i++) 26 | dp[i][0] = -INF; 27 | for (int j = 0; j <= k; j++) 28 | dp[0][j] = -INF; 29 | dp[0][0] = 0; 30 | for (int j = 1; j <= k; j++) 31 | calculateDP(1, n, j, 0, n - 1); 32 | return dp[n][k]; 33 | } 34 | -------------------------------------------------------------------------------- /code/data_structures/bit2d_sparse.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define mp make_pair 5 | using namespace std; 6 | using namespace __gnu_pbds; 7 | using pii = pair; 8 | typedef tree, rb_tree_tag, tree_order_statistics_node_update> OST; 9 | const int MAXN = 200001; 10 | // Time complexity : O(Q * log(N)^2) 11 | // Space complexity : O(Q * log(N)) 12 | namespace Bit2d{ 13 | OST bit[MAXN]; 14 | void add(int x, int y){ 15 | for(int i = x; i < MAXN; i += i & -i) 16 | bit[i].insert(mp(y, x)); 17 | } 18 | void remove(int x, int y){ 19 | for(int i = x; i < MAXN; i += i & -i) 20 | bit[i].erase(mp(y, x)); 21 | } 22 | int get(int x, int y){ 23 | int ans = 0; 24 | for(int i = x; i > 0; i -= i & -i) 25 | ans += bit[i].order_of_key(mp(y+1, 0)); 26 | return ans; 27 | } 28 | int get(int a1, int b1, int a2, int b2){ 29 | return get(a2, b2) - get(a2, b1 - 1) - get(a1 - 1, b2) + get(a1 - 1, b1 - 1); 30 | } 31 | }; -------------------------------------------------------------------------------- /code/data_structures/queue_query.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class QueueQuery{ 4 | private: 5 | typedef long long t_queue; 6 | stack> s1, s2; 7 | t_queue cmp(t_queue a, t_queue b){ 8 | return min(a, b); 9 | } 10 | void move(){ 11 | if (s2.empty()){ 12 | while (!s1.empty()){ 13 | t_queue element = s1.top().first; 14 | s1.pop(); 15 | t_queue result = s2.empty() ? element : cmp(element, s2.top().second); 16 | s2.push({element, result}); 17 | } 18 | } 19 | } 20 | public: 21 | void push(t_queue x){ 22 | t_queue result = s1.empty() ? x : cmp(x, s1.top().second); 23 | s1.push({x, result}); 24 | } 25 | void pop(){ 26 | move(); 27 | s2.pop(); 28 | } 29 | t_queue front(){ 30 | move(); 31 | return s2.top().first; 32 | } 33 | t_queue query(){ 34 | if (s1.empty() || s2.empty()) 35 | return s1.empty() ? s2.top().second : s1.top().second; 36 | else 37 | return cmp(s1.top().second, s2.top().second); 38 | } 39 | t_queue size(){ 40 | return s1.size() + s2.size(); 41 | } 42 | }; -------------------------------------------------------------------------------- /code/dynamic_programming/knuth_optimization.tex: -------------------------------------------------------------------------------- 1 | Reduces the complexity from $O(n^3)$ to $O(n^2)$ of PD's in the following ways (and other variants): 2 | \begin{equation} 3 | dp[i][j] = C[i][j] + \min_{i < k < j}(dp[i][k] + dp[k][j]), \; caso \; base: \; dp[i][i] 4 | \end{equation} 5 | \begin{equation} 6 | dp[i][j] = \min_{i < k < j}(dp[i][k] + C[i][k]), \; caso \; base: \; dp[i][i] 7 | \end{equation} 8 | \begin{itemize} 9 | \itemsep0em 10 | \item $C[i][j] =$ the cost only depends on $i$ and $j$. 11 | \item $opt[i][j] = k$ is the optimal value that maximizes $dp[i][j]$. 12 | \end{itemize} 13 | The following conditions must be met: 14 | \begin{itemize} 15 | \itemsep0em 16 | \item Foursquare inequality on $C$: $C[a][c] + C[b][d] \leq C[a][d] + C[b][c]$, $a \leq b \leq c \leq d$. 17 | \item Monotonicity on $C$: $C[b][c] \leq C[a][d]$, $a \leq b \leq c \leq d$. 18 | \end{itemize} 19 | Or the following condition: 20 | \begin{itemize} 21 | \itemsep0em 22 | \item $opt$ increasing in rows and columns: $opt[i][j-1] \leq opt[i][j] \leq opt[i+1][j]$. 23 | \end{itemize} 24 | -------------------------------------------------------------------------------- /test/data_structures/range_color_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/range_color.h" 2 | 3 | void testRangeColor(){ 4 | RangeColor rc(1, 10, 1); 5 | assert(rc.countColor(0) == 10 and rc.countColor(1) == 0); 6 | rc.set(2, 5, 1); 7 | assert(rc.countColor(0) == 6 and rc.countColor(1) == 4); 8 | rc.set(1, 10, 1); 9 | assert(rc.countColor(0) == 0 and rc.countColor(1) == 10); 10 | rc.set(2, 4, 0); 11 | assert(rc.countColor(0) == 3 and rc.countColor(1) == 7); 12 | rc.set(3, 3, 0); 13 | assert(rc.countColor(0) == 3 and rc.countColor(1) == 7); 14 | rc.set(9, 10, 0); 15 | assert(rc.countColor(0) == 5 and rc.countColor(1) == 5); 16 | rc.set(1, 1, 0); 17 | assert(rc.countColor(0) == 6 and rc.countColor(1) == 4); 18 | rc.set(5, 6, 0); 19 | assert(rc.countColor(0) == 8 and rc.countColor(1) == 2); 20 | rc.set(8, 8, 0); 21 | assert(rc.countColor(0) == 9 and rc.countColor(1) == 1); 22 | rc.set(7, 7, 0); 23 | assert(rc.countColor(0) == 10 and rc.countColor(1) == 0); 24 | } 25 | 26 | int main(){ 27 | testRangeColor(); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /code/math/fraction.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long f_type; 4 | //Representation of the a/b 5 | struct Fraction { 6 | f_type a, b; 7 | Fraction(f_type _a = 0): a(_a), b(1){} 8 | Fraction(f_type _a, f_type _b) { 9 | f_type g = __gcd(_a, _b); 10 | a = _a/g; 11 | b = _b/g; 12 | if(b < 0){ 13 | a = -a; 14 | b = -b; 15 | } 16 | } 17 | Fraction operator+(Fraction oth) { 18 | return Fraction(a*oth.b + oth.a*b, b*oth.b); 19 | } 20 | Fraction operator-(Fraction oth) { 21 | return Fraction(a*oth.b - oth.a*b, b*oth.b); 22 | } 23 | Fraction operator*(Fraction oth) { 24 | return Fraction(a*oth.a, b*oth.b); 25 | } 26 | Fraction operator/(Fraction oth) { 27 | return Fraction(a*oth.b, b*oth.a); 28 | } 29 | bool operator>=(Fraction oth){ 30 | return ((*this) - oth).a >= 0; 31 | } 32 | bool operator==(Fraction oth){ 33 | return a == oth.a and b == oth.b; 34 | } 35 | operator f_type() {return a/b;} 36 | operator double() {return double(a)/b;} 37 | }; 38 | -------------------------------------------------------------------------------- /code/theorems_and_formulas/binomial_coefficients.tex: -------------------------------------------------------------------------------- 1 | $ (a+b)^n = \binom n 0 a^n + \binom n 1 a^{n-1} b + \binom n 2 a^{n-2} b^2 + \cdots + \binom n k a^{n-k} b^k + \cdots + \binom n n b^n $ 2 | 3 | Pascal's Triangle: 4 | $ \binom n k = \binom {n-1} {k-1} + \binom {n-1} k $ 5 | 6 | Symmetry rule: 7 | $ \binom n k = \binom n {n-k} $ 8 | 9 | Factoring in: 10 | $ \binom n k = \frac n k \binom {n-1} {k-1} $ 11 | 12 | Sum over $k$: 13 | $ \sum_{k = 0}^n \binom n k = 2 ^ n $ 14 | 15 | Sum over $n$: 16 | $ \sum_{m = 0}^n \binom m k = \binom {n + 1} {k + 1} $ 17 | 18 | Sum over $n$ and $k$: 19 | $ \sum_{k = 0}^m \binom {n + k} k = \binom {n + m + 1} m $ 20 | 21 | Sum of the squares: 22 | $ {\binom n 0}^2 + {\binom n 1}^2 + \cdots + {\binom n n}^2 = \binom {2n} n $ 23 | 24 | Weighted sum: 25 | $ 1 \binom n 1 + 2 \binom n 2 + \cdots + n \binom n n = n 2^{n-1} $ 26 | 27 | Connection with the Fibonacci numbers: 28 | $ \binom n 0 + \binom {n-1} 1 + \cdots + \binom {n-k} k + \cdots + \binom 0 n = F_{n+1} $ 29 | 30 | More formulas: 31 | $ \sum_{k=0}^m (-1)^k \cdot \binom{n}{k} = (-1)^m \cdot \binom{n-1}{m} $ -------------------------------------------------------------------------------- /test/data_structures/policy_based_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/policy_based_tree.h" 2 | 3 | void orderedSetTest(){ 4 | ordered_set st; 5 | st.insert(4); 6 | st.insert(1); 7 | st.insert(3); 8 | assert(*st.find_by_order(0) == 1); 9 | assert(*st.find_by_order(1) == 3); 10 | assert(*st.find_by_order(2) == 4); 11 | 12 | assert(st.order_of_key(1) == 0); 13 | assert(st.order_of_key(3) == 1); 14 | assert(st.order_of_key(4) == 2); 15 | } 16 | 17 | void orderedMapTest(){ 18 | ordered_map mp; 19 | mp[4] = 1; 20 | mp[1] = -2; 21 | mp[3] = 0; 22 | assert(mp.find_by_order(0)->first == 1); 23 | assert(mp.find_by_order(0)->second == -2); 24 | assert(mp.find_by_order(1)->first == 3); 25 | assert(mp.find_by_order(1)->second == 0); 26 | assert(mp.find_by_order(2)->first == 4); 27 | assert(mp.find_by_order(2)->second == 1); 28 | 29 | assert(mp.order_of_key(1) == 0); 30 | assert(mp.order_of_key(3) == 1); 31 | assert(mp.order_of_key(4) == 2); 32 | } 33 | 34 | int main(){ 35 | orderedSetTest(); 36 | orderedMapTest(); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /code/graph/tree_id.h: -------------------------------------------------------------------------------- 1 | #include "centroid.h" 2 | #define F first 3 | #define S second 4 | namespace TreeID{ 5 | int id=0; 6 | map, int> mpId; 7 | vector adj[MAXN]; 8 | int treeID(int u, int p){ 9 | map mp; 10 | for(int to: adj[u]){ 11 | if(to != p) 12 | mp[treeID(to, u)]++; 13 | } 14 | if(!mpId.count(mp)) 15 | mpId[mp] = ++id; 16 | return mpId[mp]; 17 | } 18 | //Returns a pair of values that represents a tree only. O((N+M)*log(M)) 19 | //0-indexed 20 | pii getTreeID(vector &edges, int n){ 21 | for(int i=0; i ans.S) 32 | swap(ans.F, ans.S); 33 | return ans; 34 | } 35 | bool isomorphic(vector &tree1, vector &tree2, int n){ 36 | return getTreeID(tree1, n) == getTreeID(tree2, n); 37 | } 38 | }; -------------------------------------------------------------------------------- /test/math/xor_and_or_convolution_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/xor_and_or_convolution.h" 2 | vector convolutionBrute(vector a, vector b){ 3 | int mx = max(a.size(), b.size()); 4 | int n = 1; 5 | while(n < mx) 6 | n <<= 1; 7 | a.resize(n, 0); b.resize(n, 0); 8 | vector ans(n, 0); 9 | for(int i=0; i a(n, 0), b(n, 0); 18 | for(int i=0; i 2 | using namespace std; 3 | struct StringHashing{ 4 | const uint64_t MOD = (1LL<<61) - 1; 5 | const int base = 31; 6 | uint64_t modMul(uint64_t a, uint64_t b){ 7 | uint64_t l1 = (uint32_t)a, h1 = a>>32, l2 = (uint32_t)b, h2 = b>>32; 8 | uint64_t l = l1*l2, m = l1*h2 + l2*h1, h = h1*h2; 9 | uint64_t ret = (l&MOD) + (l>>61) + (h << 3) + (m >> 29) + ((m << 35) >> 3) + 1; 10 | ret = (ret & MOD) + (ret>>61); 11 | ret = (ret & MOD) + (ret>>61); 12 | return ret-1; 13 | } 14 | int getInt(char c){ 15 | return c-'a'+1; 16 | } 17 | vector hs, p; 18 | //Public: 19 | StringHashing(string s){ 20 | int n = s.size(); 21 | hs.resize(n); p.resize(n); 22 | p[0] = 1; 23 | hs[0] = getInt(s[0]); 24 | for(int i=1; i r) return -1; 31 | uint64_t res = hs[r]; 32 | if(l > 0) res = (res + MOD - modMul(p[r-l+1], hs[l-1]))%MOD; 33 | return res; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /code/math/lagrange_poly.h: -------------------------------------------------------------------------------- 1 | #include "modular_int.h" 2 | namespace LagrangePoly { 3 | const int MAXN = 100010; 4 | modInt den[MAXN], fat[MAXN], ifat[MAXN], l[MAXN], r[MAXN]; 5 | void build(int n){ 6 | fat[0] = 1; 7 | for(int i=1; i<=n; i++) 8 | fat[i] = fat[i-1] * i; 9 | ifat[n] = fat[n].inv(); 10 | for(int i=n-1; i>=0; i--) 11 | ifat[i] = ifat[i+1] * (i+1); 12 | } 13 | // f(i) = y[i] 14 | //return f(x0) 15 | modInt getVal(vector &y, ll x0) { 16 | int n = y.size(); 17 | assert(fat[n-1] != 0); 18 | modInt x = x0; 19 | for(int i = 0; i < n; i++) { 20 | den[i] = ifat[n - i - 1] * ifat[i]; 21 | if((n - i - 1) % 2 == 1) { 22 | den[i] = -den[i]; 23 | } 24 | } 25 | l[0] = 1; 26 | for(int i = 1; i < n; i++) { 27 | l[i] = l[i - 1] * (x - (i - 1)); 28 | } 29 | r[n - 1] = 1; 30 | for(int i = n - 2; i >= 0; i--) { 31 | r[i] = r[i + 1] * (x - (i + 1)); 32 | } 33 | modInt ans = 0; 34 | for(int i = 0; i < n; i++) { 35 | modInt li = l[i] * r[i] * den[i]; 36 | ans = (ans + (y[i] * li)); 37 | } 38 | return ans; 39 | } 40 | }; -------------------------------------------------------------------------------- /code/graph/prim.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | typedef pair pii; 5 | const int MAXN = 500010; 6 | namespace Prim{ 7 | vector adj[MAXN]; 8 | int weight[MAXN]; 9 | bool seen[MAXN]; 10 | int n; 11 | void init(int n1){ 12 | n = n1; 13 | for(int i=0; i, greater > st; 26 | st.push(pii(weight[0], 0)); 27 | ll ans = 0; 28 | while(!st.empty()){ 29 | int u = st.top().second; 30 | st.pop(); 31 | if(seen[u]) 32 | continue; 33 | seen[u] = true; 34 | ans += weight[u]; 35 | for(auto [edge, to]: adj[u]){ 36 | if(!seen[to] and (edge < weight[to])){ 37 | weight[to] = edge; 38 | st.emplace(weight[to], to); 39 | } 40 | } 41 | } 42 | return ans; 43 | } 44 | }; -------------------------------------------------------------------------------- /code/math/function_root_using_newton.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long double ld; 4 | struct Poly{ 5 | vector v; 6 | Poly(vector &v1):v(v1){} 7 | //return f(x) 8 | ld f(ld x){ 9 | ld ans = 0; 10 | ld e = 1; 11 | int n = v.size(); 12 | for(int i=0; i aux(g); 45 | for(int i=g; i>=1; i--){ 46 | aux[i-1] = v[i]; 47 | v[i-1] += a*aux[i-1]; 48 | } 49 | v = aux; 50 | } 51 | }; -------------------------------------------------------------------------------- /test/data_structures/sqrt_decomposition_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/sqrt_decomposition.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 1000; 4 | int v[MAXN + 10]; 5 | 6 | int randWithNeg(){ 7 | if (rand() % 2) 8 | return (rand() % MAXX); 9 | else 10 | return -(rand() % MAXX); 11 | } 12 | 13 | long long rangeSum(int a, int b){ 14 | long long ans = v[a]; 15 | for (int i = a + 1; i <= b; i++) 16 | ans = (ans + v[i]); 17 | return ans; 18 | } 19 | 20 | void testUpdateAndQuery(){ 21 | srand(42); 22 | for (int i = 0; i < MAXN; i++){ 23 | v[i] = randWithNeg(); 24 | } 25 | 26 | SqrtDecomposition sdSum(v, v + MAXN); 27 | for (int i = 0; i < MAXN; i++){ 28 | for (int j = i; j < MAXN; j++){ 29 | assert(sdSum.query(i, j) == rangeSum(i, j)); 30 | } 31 | } 32 | for (int i = 0; i < MAXN; i++){ 33 | for (int j = i; j < MAXN; j++){ 34 | assert(sdSum.query(i, j) == rangeSum(i, j)); 35 | v[j] = randWithNeg(); 36 | sdSum.update(j, v[j]); 37 | assert(sdSum.query(i, j) == rangeSum(i, j)); 38 | } 39 | } 40 | } 41 | 42 | int main(){ 43 | testUpdateAndQuery(); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /test/data_structures/sqrt_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/sqrt_tree.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 1000; 4 | 5 | int randWithNeg(){ 6 | if (rand() % 2) 7 | return (rand() % MAXX); 8 | else 9 | return -(rand() % MAXX); 10 | } 11 | 12 | long long rangeOr(vector &v, int a, int b){ 13 | long long ans = v[a]; 14 | for (int i = a + 1; i <= b; i++) 15 | ans = (ans | v[i]); 16 | return ans; 17 | } 18 | 19 | void testUpdateAndQuery(){ 20 | srand(42); 21 | vector v(MAXN); 22 | for (int i = 0; i < MAXN; i++){ 23 | v[i] = randWithNeg(); 24 | } 25 | 26 | SqrtTree stSum(v.begin(), v.end()); 27 | for (int i = 0; i < MAXN; i++){ 28 | for (int j = i; j < MAXN; j++){ 29 | assert(stSum.query(i, j) == rangeOr(v, i, j)); 30 | } 31 | } 32 | 33 | for (int i = 0; i < MAXN; i++){ 34 | for (int j = i; j < MAXN; j++){ 35 | assert(stSum.query(i, j) == rangeOr(v, i, j)); 36 | v[j] = randWithNeg(); 37 | stSum.update(j, v[j]); 38 | assert(stSum.query(i, j) == rangeOr(v, i, j)); 39 | } 40 | } 41 | } 42 | 43 | int main(){ 44 | testUpdateAndQuery(); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /test/graph/topological_sort_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/topological_sort.h" 2 | typedef pair pii; 3 | bool testTopologicalSort(int n, vector edges){ 4 | vector ts = TopologicalSort::order(n, edges); 5 | vector time(n); 6 | for (int i = 0; i < n; i++) 7 | time[ts[i]] = i; 8 | for (pii p : edges){ 9 | if (time[p.first] > time[p.second]) 10 | return false; 11 | } 12 | return true; 13 | } 14 | void test1(){ 15 | vector edges; 16 | edges.emplace_back(0, 1); 17 | edges.emplace_back(0, 2); 18 | edges.emplace_back(1, 3); 19 | edges.emplace_back(2, 3); 20 | edges.emplace_back(3, 4); 21 | edges.emplace_back(3, 5); 22 | edges.emplace_back(3, 6); 23 | edges.emplace_back(6, 7); 24 | assert(testTopologicalSort(8, edges)); 25 | } 26 | void test2(){ 27 | vector edges; 28 | edges.emplace_back(0, 1); 29 | edges.emplace_back(1, 2); 30 | edges.emplace_back(1, 3); 31 | edges.emplace_back(2, 3); 32 | edges.emplace_back(3, 4); 33 | edges.emplace_back(3, 5); 34 | edges.emplace_back(3, 6); 35 | assert(testTopologicalSort(7, edges)); 36 | } 37 | int main(){ 38 | test1(); 39 | test2(); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /code/data_structures/line_container.h: -------------------------------------------------------------------------------- 1 | #include 2 | #pragma once 3 | using ll = long long; 4 | using namespace std; 5 | struct Line { 6 | mutable ll k, m, p; 7 | bool operator<(const Line& o) const { return k < o.k; } 8 | bool operator<(ll x) const { return p < x; } 9 | }; 10 | struct LineContainer : multiset> { 11 | // (for doubles, use inf = 1/.0, div(a,b) = a/b 12 | static const ll inf = LLONG_MAX; 13 | ll div(ll a, ll b) { // floored division 14 | return a / b - ((a ^ b) < 0 && a % b); 15 | } 16 | bool isect(iterator x, iterator y) { 17 | if (y == end()) return x->p = inf, 0; 18 | if (x->k == y->k) x->p = x->m > y->m ? inf : -inf; 19 | else x->p = div(y->m - x->m, x->k - y->k); 20 | return x->p >= y->p; 21 | } 22 | void add(ll k, ll m) { 23 | auto z = insert({k, m, 0}), y = z++, x = y; 24 | while (isect(y, z)) z = erase(z); 25 | if (x != begin() && isect(--x, y)) isect(x, y = erase(y)); 26 | while ((y = x) != begin() && (--x)->p >= y->p) 27 | isect(x, erase(y)); 28 | } 29 | ll getMax(ll x) { 30 | assert(!empty()); 31 | auto l = *lower_bound(x); 32 | return l.k * x + l.m; 33 | } 34 | }; -------------------------------------------------------------------------------- /code/data_structures/sqrt_decomposition.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | struct SqrtDecomposition{ 4 | typedef long long t_sqrt; 5 | int sqrtLen; 6 | vector block; 7 | vector v; 8 | template 9 | SqrtDecomposition(MyIterator begin, MyIterator end){ 10 | int n = end - begin; 11 | sqrtLen = (int)sqrt(n + .0) + 1; 12 | v.resize(n); 13 | block.resize(sqrtLen + 5); 14 | for (int i = 0; i < n; i++, begin++){ 15 | v[i] = (*begin); 16 | block[i / sqrtLen] += v[i]; 17 | } 18 | } 19 | //0-indexed 20 | void update(int idx, t_sqrt new_value){ 21 | t_sqrt d = new_value - v[idx]; 22 | v[idx] += d; 23 | block[idx / sqrtLen] += d; 24 | } 25 | //0-indexed [l, r] 26 | t_sqrt query(int l, int r){ 27 | t_sqrt sum = 0; 28 | int c_l = l / sqrtLen, c_r = r / sqrtLen; 29 | if (c_l == c_r){ 30 | for (int i = l; i <= r; i++) 31 | sum += v[i]; 32 | }else{ 33 | for (int i = l, end = (c_l + 1) * sqrtLen - 1; i <= end; i++) 34 | sum += v[i]; 35 | for (int i = c_l + 1; i <= c_r - 1; i++) 36 | sum += block[i]; 37 | for (int i = c_r * sqrtLen; i <= r; i++) 38 | sum += v[i]; 39 | } 40 | return sum; 41 | } 42 | }; -------------------------------------------------------------------------------- /test/graph/articulation_point_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/articulation_point.h" 2 | 3 | void test1(){ 4 | AP::init(8); 5 | AP::addEdge(0, 1); 6 | AP::addEdge(1, 2); 7 | AP::addEdge(1, 3); 8 | AP::addEdge(2, 3); 9 | AP::addEdge(3, 4); 10 | AP::addEdge(6, 7); 11 | auto ret = AP::findArticulationPoint(); 12 | vector ans = {0, 1, 0, 1, 0, 0, 0, 0}; 13 | assert(ret == ans); 14 | } 15 | 16 | void test2(){ //AC: https://vjudge.net/problem/UVA-315 17 | ios_base::sync_with_stdio(false); cin.tie(NULL); 18 | while(true){ 19 | int n; 20 | cin >> n; 21 | if(n == 0) 22 | break; 23 | AP::init(n); 24 | cin.ignore(); 25 | while(true){ 26 | string line; 27 | getline(cin, line); 28 | if(line == "0") 29 | break; 30 | stringstream ss; 31 | ss << line; 32 | int a; 33 | ss >> a; 34 | int b; 35 | while(ss>>b) 36 | AP::addEdge(a-1, b-1); 37 | } 38 | auto isAP = AP::findArticulationPoint(); 39 | int ans = 0; 40 | for(bool b: isAP) 41 | ans += b; 42 | cout << ans << endl; 43 | } 44 | } 45 | 46 | int main(){ 47 | test1(); 48 | //test2(); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /code/graph/strongly_connected_component.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef pair pii; 4 | namespace SCC{ 5 | vector> adj, revAdj; 6 | vector visited; 7 | vector ts, component; 8 | void dfs1(int u){ 9 | visited[u] = true; 10 | for(int to : adj[u]){ 11 | if(!visited[to]) 12 | dfs1(to); 13 | } 14 | ts.push_back(u); 15 | } 16 | void dfs2(int u, int c){ 17 | component[u] = c; 18 | for(int to : revAdj[u]){ 19 | if(component[to] == -1) 20 | dfs2(to, c); 21 | } 22 | } 23 | vector scc(int n, vector &edges){ 24 | adj.assign(n, vector()); 25 | revAdj.assign(n, vector()); 26 | visited.assign(n, false); 27 | component.assign(n, -1); 28 | for(auto [a, b] : edges){ 29 | adj[a].push_back(b); 30 | revAdj[b].push_back(a); 31 | } 32 | ts.clear(); 33 | for (int i = 0; i < n; i++){ 34 | if (!visited[i]) 35 | dfs1(i); 36 | } 37 | reverse(ts.begin(), ts.end()); 38 | int comp = 0; 39 | for (int u : ts){ 40 | if (component[u] == -1) 41 | dfs2(u, comp++); 42 | } 43 | return component; 44 | } 45 | } -------------------------------------------------------------------------------- /code/graph/bridge.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int MAXN = 500010; 4 | typedef pair pii; 5 | namespace Bridge{ 6 | vector adj[MAXN]; 7 | vector visited; 8 | vector tin, low; 9 | int timer, n; 10 | vector bridges; 11 | void init(int n1){ 12 | n = n1; 13 | for(int i=0; i tin[u]) 30 | bridges.push_back({u, to}); 31 | } 32 | } 33 | } 34 | vector findBridges() { 35 | timer = 0; 36 | visited.assign(n, false); 37 | tin.assign(n, -1); 38 | low.assign(n, -1); 39 | bridges.clear(); 40 | for (int i = 0; i < n; i++) { 41 | if (!visited[i]) 42 | dfs(i); 43 | } 44 | return bridges; 45 | } 46 | }; -------------------------------------------------------------------------------- /code/theorems_and_formulas/formulas.tex: -------------------------------------------------------------------------------- 1 | Count the number of ways to partition a set of $n$ labelled objects into $k$ nonempty labelled subsets. 2 | 3 | $$f(n, k) = \sum_{i=0}^{k}(-1)^i\binom{k}{i}(k-i)^n$$ 4 | 5 | Stirling Number 2nd: Partitions of an $n$ element set into $k$ not-empty set. 6 | Or count the number of ways to partition a set of $n$ labelled objects into $k$ nonempty unlabelled subsets. 7 | 8 | $$S_{2nd}(n, k) = \begin{Bmatrix} n \\ k \end{Bmatrix} = \frac{1}{k!}\sum_{i=0}^{k}(-1)^i\binom{k}{i}(k-i)^n$$ 9 | 10 | Euler's formula: $f = e - v + 2$ 11 | 12 | Euler's formula to $n$ Lines or Segment if there is no three lines/segments that contains the same point: $R = intersects + component - n$ 13 | 14 | Number of regions in a planar graph: $R = E - V + C + 1$ where C is the number of connected components 15 | 16 | Given $a$ and $b$ co-prime, $n = a \cdot x + b \cdot y$ where $x \ge 0$ and $y \ge 0$. 17 | You are required to find the least value of n, such that all currency values greater than or equal to $n$ can be made using any number of coins of denomination $a$ and $b$: $n = (a-1)*(b-1)$ 18 | 19 | generalization of the above problem, $n$ is multiple of $gcd(a, b)$: $n = lcm(a, b) - a - b + gcd(a, b)$ -------------------------------------------------------------------------------- /test/graph/arborescence_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/arborescence.h" 2 | void test1(){ 3 | vector v; 4 | v.push_back(Edge({1, 0, 10})); 5 | vector ans; 6 | assert(dmst(2, 0, v).first == -1); 7 | assert(dmst(2, 1, v).first == 10); 8 | assert(dmstAnyRoot(2, v).first == 10); 9 | } 10 | void test2(){ 11 | vector v; 12 | v.push_back(Edge({0, 1, 10})); 13 | v.push_back(Edge({0, 2, 10})); 14 | v.push_back(Edge({1, 3, 20})); 15 | v.push_back(Edge({2, 3, 30})); 16 | assert(dmst(4, 0, v).first == 40); 17 | assert(dmstAnyRoot(4, v).first == 40); 18 | } 19 | void test3(){ 20 | vector v; 21 | v.push_back(Edge({0, 1, 10})); 22 | v.push_back(Edge({1, 2, 20})); 23 | v.push_back(Edge({2, 0, 30})); 24 | v.push_back(Edge({2, 3, 100})); 25 | assert(dmst(4, 0, v).first == 130); 26 | assert(dmstAnyRoot(4, v).first == 130); 27 | } 28 | void test4(){ 29 | assert(true); // AC in https://codeforces.com/gym/102483/problem/F 30 | assert(true); // AC in https://vjudge.net/problem/UVA-11183 31 | assert(true); // AC in https://judge.yosupo.jp/problem/directedmst 32 | } 33 | int main(){ 34 | test1(); 35 | test2(); 36 | test3(); 37 | test4(); 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /code/strings/manacher.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | // source: https://github.com/brunomaletta/Biblioteca/blob/master/Codigo/Strings/manacher.cpp 4 | // ret[2*i] = larger size palindrome centered on i 5 | // ret[2*i+1] = larger size palindrome centered on i and i + 1 6 | vector manacher(const string &s) { 7 | int l = 0, r = -1, n = s.size(); 8 | vector d1(n), d2(n); 9 | for (int i = 0; i < n; i++) { 10 | int k = i > r ? 1 : min(d1[l+r-i], r-i); 11 | while (i+k < n && i-k >= 0 && s[i+k] == s[i-k]) k++; 12 | d1[i] = k--; 13 | if (i+k > r) l = i-k, r = i+k; 14 | } 15 | l = 0, r = -1; 16 | for (int i = 0; i < n; i++) { 17 | int k = i > r ? 0 : min(d2[l+r-i+1], r-i+1); k++; 18 | while (i+k <= n && i-k >= 0 && s[i+k-1] == s[i-k]) k++; 19 | d2[i] = --k; 20 | if (i+k-1 > r) l = i-k, r = i+k-1; 21 | } 22 | vector ret(2*n-1); 23 | for (int i = 0; i < n; i++) ret[2*i] = 2*d1[i]-1; 24 | for (int i = 0; i < n-1; i++) ret[2*i+1] = 2*d2[i+1]; 25 | return ret; 26 | } 27 | struct Palindrome { 28 | vector man; 29 | Palindrome(const string &s) : man(manacher(s)) {} 30 | bool isPalindrome(int i, int j) { 31 | return man[i+j] >= j-i+1; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /test/graph/bfs01_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/bfs01.h" 2 | 3 | void test1(){ 4 | int n=7; 5 | BFS01::init(n); 6 | BFS01::addEdge(0, 1, 0); 7 | BFS01::addEdge(1, 0, 1); 8 | BFS01::addEdge(2, 1, 0); 9 | BFS01::addEdge(1, 2, 1); 10 | BFS01::addEdge(2, 3, 0); 11 | BFS01::addEdge(3, 2, 1); 12 | BFS01::addEdge(6, 3, 0); 13 | BFS01::addEdge(3, 6, 1); 14 | BFS01::addEdge(5, 1, 0); 15 | BFS01::addEdge(1, 5, 1); 16 | BFS01::addEdge(4, 5, 0); 17 | BFS01::addEdge(5, 4, 1); 18 | BFS01::addEdge(6, 4, 0); 19 | BFS01::addEdge(4, 6, 1); 20 | 21 | auto d = BFS01::solve(0); 22 | assert(d[0] == 0); 23 | assert(d[1] == 0); 24 | assert(d[2] == 1); 25 | assert(d[6] == 2); 26 | } 27 | 28 | void test2(){// https://www.codechef.com/problems/REVERSE 29 | ios_base::sync_with_stdio(false); cin.tie(NULL); 30 | int n, m; 31 | cin >> n >> m; 32 | BFS01::init(n); 33 | for(int i=0; i> a >> b; a--; b--; 36 | BFS01::addEdge(a, b, 0); 37 | BFS01::addEdge(b, a, 1); 38 | } 39 | auto d = BFS01::solve(0); 40 | if(d[n-1] == INF) 41 | cout << -1 << endl; 42 | else 43 | cout << d[n-1] << endl; 44 | } 45 | int main() { 46 | test1(); 47 | //test2(); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /test/dynamic_programming/alien_trick_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/dynamic_programming/alien_trick.h" 2 | 3 | const int MAXN = 1000010; 4 | pll dp[MAXN][2]; 5 | vector v; 6 | int n; 7 | 8 | pll solveDP(ll C){ 9 | //Case base 10 | dp[n][0] = pll(0, 0); 11 | dp[n][1] = pll(0, 0); 12 | for(int i=n-1; i>=0; i--){ 13 | { //Close 14 | pll op1 = dp[i+1][false]; 15 | 16 | pll op2 = dp[i+1][true]; 17 | op2.F += (v[i] - C); 18 | op2.S -= 1; 19 | dp[i][false] = max(op1, op2); 20 | } 21 | { // Open 22 | pll op1 = dp[i][false]; 23 | 24 | pll op2 = dp[i+1][true]; 25 | op2.F += v[i]; 26 | dp[i][true] = max(op1, op2); 27 | } 28 | } 29 | pll ans = dp[0][false]; 30 | ans.S = -ans.S; 31 | return ans; 32 | } 33 | 34 | void test(){ 35 | // Case 01 36 | n = 6; 37 | v = {1, -2, 3, -4, 5, -6}; 38 | assert(solveMax(4) == 9); 39 | 40 | // Case 02 41 | n = 9; 42 | v = {1, 5, -3, 4, -10, 1, 2, -4, 1}; 43 | assert(solveMax(2) == 10); 44 | 45 | // Case 03 46 | n = 5; 47 | v = {-10, -20, -30, -40, -50}; 48 | assert(solveMax(2) == 0); 49 | 50 | assert(true); // AC: https://neps.academy/exercise/484 51 | } 52 | 53 | int main() { 54 | test(); 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /code/geometry/convex_hull_trick.h: -------------------------------------------------------------------------------- 1 | #include "basic_geometry.h" 2 | using namespace std; 3 | struct LineCHT{ 4 | ftype k, b; 5 | int id; 6 | LineCHT() {} 7 | LineCHT(ftype k, ftype b, int id=-1): k(k), b(b), id(id) {} 8 | }; 9 | struct ConvexHullTrick{ 10 | vector hull, vecs; 11 | ConvexHullTrick(){} 12 | ConvexHullTrick(vector v){ 13 | sort(v.begin(), v.end(), [&](LineCHT a, LineCHT b){ 14 | return lt(a.k, b.k); 15 | }); 16 | for(auto l: v) 17 | add_line(l.k, l.b); 18 | } 19 | //Here we will assume that when linear functions are added, their k only increases and we want to find minimum values. 20 | void add_line(ftype k, ftype b) { 21 | Point2d nw(k, b); 22 | while(!vecs.empty() && lt(dot(vecs.back(), nw - hull.back()), 0)) { 23 | hull.pop_back(); 24 | vecs.pop_back(); 25 | } 26 | if(!hull.empty()) 27 | vecs.push_back(perpL(nw - hull.back())); 28 | hull.push_back(nw); 29 | } 30 | //Find minimum value 31 | ftLong get(ftype x) { 32 | Point2d query(x, 1); 33 | auto it = lower_bound(vecs.begin(), vecs.end(), query, [](Point2d a, Point2d b) { 34 | return gt(cross(a, b), 0); 35 | }); 36 | return dot(query, hull[it - vecs.begin()]); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /test/geometry/convex_polygon_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/geometry/convex_polygon.h" 2 | 3 | void test1(){ 4 | vector v; 5 | v.emplace_back(0, 0); 6 | v.emplace_back(0, 10); 7 | v.emplace_back(10, 0); 8 | v.emplace_back(10, 10); 9 | ConvexPolygon pol(v); 10 | assert(pol.pointInPolygon(Point2d(5, 5)) == true); 11 | assert(pol.pointInPolygon(Point2d(0, 0)) == true); 12 | assert(pol.pointInPolygon(Point2d(0, 5)) == true); 13 | assert(pol.pointInPolygon(Point2d(-1, 0)) == false); 14 | assert(pol.pointInPolygon(Point2d(0, 11)) == false); 15 | assert(pol.pointInPolygon(Point2d(-1, 5)) == false); 16 | assert(pol.pointInPolygon(Point2d(11, 11)) == false); 17 | } 18 | void test2(){ 19 | 20 | int n, m, k; 21 | 22 | cin >> n >> m >> k; 23 | vector v(n); 24 | 25 | for(int i=0; i> v[i].x >> v[i].y; 27 | } 28 | ConvexPolygon pol(v); 29 | for(int i=0; i> p.x >> p.y; 32 | k -= pol.pointInPolygon(p); 33 | } 34 | 35 | if(k <= 0) 36 | cout << "YES" << endl; 37 | else 38 | cout << "NO" << endl; 39 | } 40 | int main() { 41 | test1(); 42 | // test2(); // AC: https://codeforces.com/problemsets/acmsguru/submission/99999/84838119 43 | return 0; 44 | } -------------------------------------------------------------------------------- /test/data_structures/segment_tree_persistent_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/segment_tree_persistent.h" 2 | 3 | void testPersistentSegtree(){ 4 | int v[] = {0, 0, 0, 0, 0, 0}; 5 | int n = 6; 6 | PerSegTree::build(n, v); 7 | assert(PerSegTree::query(0, 5, 0) == 0); 8 | 9 | PerSegTree::update(1, 2); 10 | assert(PerSegTree::query(0, 5, 0) == 0); 11 | assert(PerSegTree::query(0, 5, 1) == 2); 12 | assert(PerSegTree::query(1, 1, 1) == 2); 13 | 14 | PerSegTree::update(3, -2); 15 | assert(PerSegTree::query(0, 5, 0) == 0); 16 | assert(PerSegTree::query(0, 5, 1) == 2); 17 | assert(PerSegTree::query(0, 5, 2) == 0); 18 | assert(PerSegTree::query(1, 1, 1) == 2); 19 | assert(PerSegTree::query(1, 1, 2) == 2); 20 | assert(PerSegTree::query(3, 3, 2) == -2); 21 | 22 | PerSegTree::update(3, 1); 23 | assert(PerSegTree::query(0, 5, 0) == 0); 24 | assert(PerSegTree::query(0, 5, 1) == 2); 25 | assert(PerSegTree::query(0, 5, 2) == 0); 26 | assert(PerSegTree::query(0, 5, 3) == 3); 27 | assert(PerSegTree::query(1, 1, 1) == 2); 28 | assert(PerSegTree::query(1, 1, 2) == 2); 29 | assert(PerSegTree::query(3, 3, 2) == -2); 30 | assert(PerSegTree::query(3, 3, 3) == 1); 31 | } 32 | int main(){ 33 | testPersistentSegtree(); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /code/math/gauss.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int INF = 0x3f3f3f3f; 4 | typedef long double ld; 5 | const ld EPS = 1e-9; 6 | int gauss(vector> a, vector &ans) { 7 | int n = (int) a.size(); 8 | int m = (int) a[0].size() - 1; 9 | vector where (m, -1); 10 | for (int col=0, row=0; col abs(a[sel][col])) 14 | sel = i; 15 | if (abs(a[sel][col]) < EPS) 16 | continue; 17 | for (int i=col; i<=m; i++) 18 | swap(a[sel][i], a[row][i]); 19 | where[col] = row; 20 | for (int i=0; i EPS) 38 | return 0; 39 | } 40 | for (int i=0; i 2 | using namespace std; 3 | // Source: https://github.com/brunomaletta/Biblioteca 4 | template struct RMQ{ 5 | vector v; 6 | int n; static const int b = 30; 7 | vector mask, t; 8 | int op(int x, int y) { return v[x] < v[y] ? x : y; } 9 | int msb(int x) { return __builtin_clz(1)-__builtin_clz(x); } 10 | int small(int r, int sz = b) { return r-msb(mask[r]&((1<& v_) : v(v_), n(v.size()), mask(n), t(n) { 12 | for (int i = 0, at = 0; i < n; mask[i++] = at |= 1) { 13 | at = (at<<1)&((1< 2 | using namespace std; 3 | typedef pair pii; 4 | template struct EulerianPath{ 5 | vector> adj; 6 | vector ans, pos; 7 | vector used; 8 | int n, m; 9 | EulerianPath(int n1){ 10 | n = n1; m = 0; 11 | adj.assign(n, vector()); 12 | } 13 | void addEdge(int a, int b) { 14 | int at = m++; 15 | adj[a].push_back({b, at}); 16 | if (!directed) adj[b].push_back({a, at}); 17 | } 18 | void dfs(int u){ 19 | stack st; 20 | st.push(u); 21 | while(!st.empty()){ 22 | u = st.top(); 23 | if(pos[u] < adj[u].size()){ 24 | auto [to, id] = adj[u][pos[u]]; 25 | pos[u]++; 26 | if(!used[id]){ 27 | used[id] = true; 28 | st.push(to); 29 | } 30 | }else{ 31 | ans.push_back(u); 32 | st.pop(); 33 | } 34 | } 35 | } 36 | // Remember to call the correct src 37 | // If you want to check if there is an answer remember to check if all |components| > 1 of the graph are connected 38 | vector getPath(int src){ 39 | pos.assign(n, 0); 40 | used.assign(m, false); 41 | ans.clear(); 42 | dfs(src); 43 | reverse(ans.begin(), ans.end()); 44 | return ans; 45 | } 46 | }; -------------------------------------------------------------------------------- /code/math/karatsuba.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | // Source: https://github.com/brunomaletta/Biblioteca/blob/master/Codigo/Matematica/karatsuba.cpp 4 | //#pragma GCC optimize("Ofast") 5 | //#pragma GCC target ("avx,avx2") 6 | template void kar(T* a, T* b, int n, T* r, T* tmp) { 7 | if (n <= 64) { 8 | for (int i = 0; i < n; i++) 9 | for (int j = 0; j < n; j++) 10 | r[i+j] += a[i] * b[j]; 11 | return; 12 | } 13 | int mid = n/2; 14 | T *atmp = tmp, *btmp = tmp+mid, *E = tmp+n; 15 | memset(E, 0, sizeof(E[0])*n); 16 | for (int i = 0; i < mid; i++) { 17 | atmp[i] = a[i] + a[i+mid]; 18 | btmp[i] = b[i] + b[i+mid]; 19 | } 20 | kar(atmp, btmp, mid, E, tmp+2*n); 21 | kar(a, b, mid, r, tmp+2*n); 22 | kar(a+mid, b+mid, mid, r+n, tmp+2*n); 23 | for (int i = 0; i < mid; i++) { 24 | T temp = r[i+mid]; 25 | r[i+mid] += E[i] - r[i] - r[i+2*mid]; 26 | r[i+2*mid] += E[i+mid] - temp - r[i+3*mid]; 27 | } 28 | } 29 | // O(n^1.58), Advantages: you can add any module 30 | template vector karatsuba(vector a, vector b) { 31 | int n = max(a.size(), b.size()); 32 | while (n&(n-1)) n++; 33 | a.resize(n), b.resize(n); 34 | vector ret(2*n), tmp(4*n); 35 | kar(&a[0], &b[0], n, &ret[0], &tmp[0]); 36 | return ret; 37 | } -------------------------------------------------------------------------------- /code/math/lagrange.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long double ld; 4 | struct PointValue{ 5 | ld x, y; 6 | PointValue(ld x0=0, ld y0=0): x(x0), y(y0){} 7 | }; 8 | void mul(vector &A, int x0){ // multiply A(x) by (x - x0) 9 | int n = A.size(); 10 | A.push_back(0); 11 | auto B = A; 12 | for(int i=n; i>=1; i--){ 13 | A[i] = A[i-1]; 14 | } 15 | A[0] = 0; 16 | for(int i=0; i &A, int x0){ // multiply A(x) by (x - x0) 20 | int g = (int)A.size() - 1; 21 | vector aux(g); 22 | for(int i=g; i>=1; i--){ 23 | aux[i-1] = A[i]; 24 | A[i-1] += x0*aux[i-1]; 25 | } 26 | A = aux; 27 | } 28 | // Change Polynomial Representation from Point-Value to Coefficient 29 | // O(n^2) 30 | vector LagrangeInterpolation(vector vp){ 31 | vector A(1, 1); 32 | int n = vp.size(); 33 | for(int i=0; i ans(n, 0); 36 | for(int i=0; i 2 | 3 | using namespace std; 4 | 5 | const int MAXN = 500010; 6 | //Articulation Point 7 | namespace AP{ 8 | vector adj[MAXN]; 9 | vector visited, isAP; 10 | vector tin, low; 11 | int timer, n; 12 | void init(int n1){ 13 | n = n1; 14 | for(int i=0; i= tin[u] && p!=-1) 32 | isAP[u] = true; 33 | ++children; 34 | } 35 | } 36 | if(p == -1 && children > 1) 37 | isAP[u] = true; 38 | } 39 | vector findArticulationPoint() { 40 | timer = 0; 41 | visited.assign(n, false); 42 | tin.assign(n, -1); 43 | low.assign(n, -1); 44 | isAP.assign(n, false); 45 | for (int i = 0; i < n; i++) { 46 | if (!visited[i]) 47 | dfs(i); 48 | } 49 | return isAP; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /code/graph/2_sat.h: -------------------------------------------------------------------------------- 1 | #include "strongly_connected_component.h" 2 | using namespace std; 3 | struct SAT{ 4 | typedef pair pii; 5 | vector edges; 6 | int n; 7 | SAT(int size){ 8 | n = 2 * size; 9 | } 10 | vector solve2SAT(){ 11 | vector vAns(n / 2, false); 12 | vector comp = SCC::scc(n, edges); 13 | for (int i = 0; i < n; i += 2){ 14 | if (comp[i] == comp[i + 1]) 15 | return vector(); 16 | vAns[i / 2] = (comp[i] > comp[i + 1]); 17 | } 18 | return vAns; 19 | } 20 | int v(int x){ 21 | if (x >= 0) 22 | return (x << 1); 23 | x = ~x; 24 | return (x << 1) ^ 1; 25 | } 26 | void add(int a, int b){ 27 | edges.push_back(pii(a, b)); 28 | } 29 | void addOr(int a, int b){ 30 | add(v(~a), v(b)); 31 | add(v(~b), v(a)); 32 | } 33 | void addImp(int a, int b){ 34 | addOr(~a, b); 35 | } 36 | void addEqual(int a, int b){ 37 | addOr(a, ~b); 38 | addOr(~a, b); 39 | } 40 | void addDiff(int a, int b){ 41 | addEqual(a, ~b); 42 | } 43 | 44 | // Using maxterms 45 | void addTruthTable(int a, int b, bool v00, bool v01, bool v10, bool v11){ 46 | if(!v00) 47 | addOr(a, b); 48 | if(!v01) 49 | addOr(a, ~b); 50 | if(!v10) 51 | addOr(~a, b); 52 | if(!v11) 53 | addOr(~a, ~b); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /test/data_structures/segment_tree_lazy_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/segment_tree_lazy.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 1000; 4 | long long v[MAXN + 10]; 5 | 6 | int randWithNeg(){ 7 | if (rand() % 2) 8 | return (rand() % MAXX); 9 | else 10 | return -(rand() % MAXX); 11 | } 12 | 13 | long long rangeSum(int a, int b){ 14 | long long ans = v[a]; 15 | for (int i = a + 1; i <= b; i++) 16 | ans = (ans + v[i]); 17 | return ans; 18 | } 19 | void rangeUpdate(int a, int b, int x){ 20 | for (int i = a; i <= b; i++) 21 | v[i] += x; 22 | } 23 | 24 | void testUpdateAndQuery(){ 25 | vector aux(MAXN); 26 | srand(42); 27 | for (int i = 0; i < MAXN; i++){ 28 | v[i] = randWithNeg(); 29 | aux[i] = v[i]; 30 | } 31 | 32 | SegTreeLazy st(aux.begin(), aux.end()); 33 | for (int i = 0; i < MAXN; i++){ 34 | for (int j = i; j < MAXN; j++){ 35 | assert(st.query(i, j) == rangeSum(i, j)); 36 | } 37 | } 38 | for (int i = 0; i < MAXN; i++){ 39 | for (int j = i; j < MAXN; j++){ 40 | assert(st.query(i, j) == rangeSum(i, j)); 41 | int x = randWithNeg(); 42 | rangeUpdate(i, j, x); 43 | st.update(i, j, x); 44 | assert(st.query(i, j) == rangeSum(i, j)); 45 | } 46 | } 47 | } 48 | 49 | int main(){ 50 | testUpdateAndQuery(); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /code/data_structures/sparse_table.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class SparseTable{ 4 | private: 5 | typedef int t_st; 6 | vector> st; 7 | vector log2; 8 | t_st neutral = 0x3f3f3f3f; 9 | int nLog; 10 | t_st join(t_st a, t_st b){ 11 | return min(a, b); 12 | } 13 | public: 14 | template 15 | SparseTable(MyIterator begin, MyIterator end){ 16 | int n = end - begin; 17 | nLog = 20; 18 | log2.resize(n + 1); 19 | log2[1] = 0; 20 | for (int i = 2; i <= n; i++) 21 | log2[i] = log2[i / 2] + 1; 22 | st.resize(n, vector(nLog, neutral)); 23 | for (int i = 0; i < n; i++, begin++) 24 | st[i][0] = (*begin); 25 | for (int j = 1; j < nLog; j++) 26 | for (int i = 0; (i + (1 << (j - 1))) < n; i++) 27 | st[i][j] = join(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 28 | } 29 | //0-indexed [a, b] 30 | t_st query(int a, int b){ 31 | int d = b - a + 1; 32 | t_st ans = neutral; 33 | for (int j = nLog - 1; j >= 0; j--){ 34 | if (d & (1 << j)){ 35 | ans = join(ans, st[a][j]); 36 | a = a + (1 << (j)); 37 | } 38 | } 39 | return ans; 40 | } 41 | //0-indexed [a, b] 42 | t_st queryRMQ(int a, int b){ 43 | int j = log2[b - a + 1]; 44 | return join(st[a][j], st[b - (1 << j) + 1][j]); 45 | } 46 | }; -------------------------------------------------------------------------------- /test/miscellaneous/mo_with_update_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/mo_with_update.h" 2 | int ans; 3 | void add(int x){ 4 | ans += x; 5 | } 6 | void remove(int x){ 7 | ans -= x; 8 | } 9 | int getAnswer(){ 10 | return ans; 11 | } 12 | void clearAnswer(){ 13 | ans = 0; 14 | } 15 | 16 | int curr[MAXN]; 17 | int brute(int i, int j){ 18 | int sum = 0; 19 | for (int k = i; k <= j; k++) 20 | sum += curr[k]; 21 | return sum; 22 | } 23 | void testMo(){ 24 | srand(time(0)); 25 | int n = 1000; 26 | for (int i = 0; i < n; i++) 27 | curr[i] = v[i] = rand() % 100000; 28 | vector vq; 29 | vector vu; 30 | vector vans; 31 | for (int i = 0; i < 5*n; i++){ 32 | int op = rand()%2; 33 | if(op == 0){ 34 | Query q; 35 | q.t = i; 36 | q.l = rand() % n; 37 | q.r = rand() % n; 38 | if (q.l > q.r) 39 | swap(q.l, q.r); 40 | vans.push_back(brute(q.l, q.r)); 41 | vq.push_back(q); 42 | }else{ 43 | Update u; 44 | u.t = i; 45 | u.pos = rand() % n; 46 | u.newV = rand() % 100000; 47 | u.oldV = curr[u.pos]; 48 | curr[u.pos] = u.newV; 49 | vu.push_back(u); 50 | } 51 | } 52 | vector vans2 = mo_s_algorithm(vq, vu); 53 | assert(vans == vans2); 54 | } 55 | int main(){ 56 | for(int i=0; i<10; i++) 57 | testMo(); 58 | 59 | return 0; 60 | } -------------------------------------------------------------------------------- /test/graph/bridge_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/bridge.h" 2 | 3 | void test1(){ 4 | Bridge::init(8); 5 | Bridge::addEdge(0, 1); 6 | Bridge::addEdge(1, 2); 7 | Bridge::addEdge(1, 3); 8 | Bridge::addEdge(2, 3); 9 | Bridge::addEdge(3, 4); 10 | Bridge::addEdge(6, 7); 11 | auto ret = Bridge::findBridges(); 12 | for(auto &p: ret) 13 | if(p.first > p.second) swap(p.first, p.second); 14 | sort(ret.begin(), ret.end()); 15 | vector ans = {pii(0, 1), pii(3, 4), pii(6, 7)}; 16 | assert(ret == ans); 17 | } 18 | 19 | void test2(){ //AC: https://vjudge.net/problem/UVA-796 20 | ios_base::sync_with_stdio(false); cin.tie(NULL); 21 | int n; 22 | while(cin >> n){ 23 | Bridge::init(n); 24 | for(int i=0; i> a >> c >> k >> c; 28 | while(k--){ 29 | int b; 30 | cin >> b; 31 | if(a < b) 32 | Bridge::addEdge(a, b); 33 | } 34 | } 35 | auto ans = Bridge::findBridges(); 36 | for(pii &p: ans) 37 | if(p.first > p.second) swap(p.first, p.second); 38 | sort(ans.begin(), ans.end()); 39 | cout << ans.size() << " critical links" << endl; 40 | for(pii p: ans) 41 | cout << p.first << " - " << p.second << endl; 42 | cout << endl; 43 | } 44 | } 45 | 46 | int main(){ 47 | test1(); 48 | //test2(); 49 | return 0; 50 | } -------------------------------------------------------------------------------- /code/data_structures/lichao_tree.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int INF = 0x3f3f3f3f; 4 | class LiChaoTree{ 5 | private: 6 | typedef int t_line; 7 | struct Line{ 8 | t_line k, b; 9 | Line() {} 10 | Line(t_line k, t_line b) : k(k), b(b) {} 11 | }; 12 | int n_tree, min_x, max_x; 13 | vector li_tree; 14 | t_line f(Line l, int x){ 15 | return l.k * x + l.b; 16 | } 17 | void add(Line nw, int v, int l, int r){ 18 | int m = (l + r) / 2; 19 | bool lef = f(nw, l) > f(li_tree[v], l); 20 | bool mid = f(nw, m) > f(li_tree[v], m); 21 | if (mid) 22 | swap(li_tree[v], nw); 23 | if (r - l == 1) 24 | return; 25 | else if (lef != mid) 26 | add(nw, 2 * v, l, m); 27 | else 28 | add(nw, 2 * v + 1, m, r); 29 | } 30 | int get(int x, int v, int l, int r){ 31 | int m = (l + r) / 2; 32 | if (r - l == 1) 33 | return f(li_tree[v], x); 34 | else if (x < m) 35 | return max(f(li_tree[v], x), get(x, 2 * v, l, m)); 36 | else 37 | return max(f(li_tree[v], x), get(x, 2 * v + 1, m, r)); 38 | } 39 | public: 40 | LiChaoTree(int mn_x, int mx_x){ 41 | min_x = mn_x; 42 | max_x = mx_x; 43 | n_tree = max_x - min_x + 5; 44 | li_tree.resize(4 * n_tree, Line(0, -INF)); 45 | } 46 | void add(t_line k, t_line b){ 47 | add(Line(k, b), 1, min_x, max_x); 48 | } 49 | t_line get(int x){ 50 | return get(x, 1, min_x, max_x); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /code/geometry/convex_hull.h: -------------------------------------------------------------------------------- 1 | #include "basic_geometry.h" 2 | using namespace std; 3 | //If accept collinear points then change for <= 4 | bool cw(Point2d a, Point2d b, Point2d c) { 5 | return lt(cross(b - a, c - b), 0); 6 | } 7 | //If accept collinear points then change for >= 8 | bool ccw(Point2d a, Point2d b, Point2d c) { 9 | return gt(cross(b - a, c - b), 0); 10 | } 11 | // Returns the points clockwise 12 | vector convex_hull(vector a){ 13 | if (a.size() == 1) 14 | return a; 15 | sort(a.begin(), a.end()); 16 | a.erase(unique(a.begin(), a.end()), a.end()); 17 | vector up, down; 18 | Point2d p1 = a[0], p2 = a.back(); 19 | up.push_back(p1); 20 | down.push_back(p1); 21 | for (int i = 1; i < (int)a.size(); i++){ 22 | if ((i == int(a.size() - 1)) || cw(p1, a[i], p2)){ 23 | while (up.size() >= 2 && !cw(up[up.size() - 2], up[up.size() - 1], a[i])) 24 | up.pop_back(); 25 | up.push_back(a[i]); 26 | } 27 | if ((i == int(a.size() - 1)) || ccw(p1, a[i], p2)){ 28 | while (down.size() >= 2 && !ccw(down[down.size() - 2], down[down.size() - 1], a[i])) 29 | down.pop_back(); 30 | down.push_back(a[i]); 31 | } 32 | } 33 | a.clear(); 34 | for (int i = 0; i < (int)up.size(); i++) 35 | a.push_back(up[i]); 36 | for (int i = down.size() - 2; i > 0; i--) 37 | a.push_back(down[i]); 38 | return a; 39 | } -------------------------------------------------------------------------------- /code/graph/tree.h: -------------------------------------------------------------------------------- 1 | #include "../data_structures/rmq.h" 2 | // build: O(N), queries: O(1) 3 | template class Tree{ 4 | private: 5 | typedef pair Edge; 6 | vector> adj; 7 | vector v, level, in; 8 | vector sum; 9 | RMQ *rmq = nullptr; 10 | int n; 11 | void dfs(int u, int p, int d, T s){ 12 | in[u] = v.size(); 13 | v.push_back(u); 14 | level.push_back(d); 15 | sum[u] = s; 16 | for (auto [to, w] : adj[u]) if(to != p){ 17 | dfs(to, u, d + 1, s + w); 18 | v.push_back(u); 19 | level.push_back(d); 20 | } 21 | } 22 | public: 23 | ~Tree(){ 24 | if(rmq != nullptr) 25 | delete rmq; 26 | } 27 | void init(int n1){ 28 | n = n1; 29 | adj.assign(n, vector()); 30 | in.resize(n); 31 | sum.resize(n); 32 | } 33 | void addEdge(int a, int b, T w = 1){ 34 | adj[a].emplace_back(b, w); 35 | adj[b].emplace_back(a, w); 36 | } 37 | void build(int root = 0){ 38 | v.clear(); level.clear(); 39 | dfs(root, -1, 0, 0); 40 | if(rmq != nullptr) 41 | delete rmq; 42 | rmq = new RMQ(level); 43 | } 44 | //O(1) 45 | int lca(int a, int b){ 46 | a = in[a], b = in[b]; 47 | if(a > b) 48 | swap(a, b); 49 | return v[rmq->getPos(a, b)]; 50 | } 51 | //O(1) 52 | T dist(int a, int b){ 53 | return sum[a] + sum[b] - 2*sum[lca(a, b)]; 54 | } 55 | }; -------------------------------------------------------------------------------- /code/math/montgomery.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | using u64 = uint64_t; 4 | using u128 = __uint128_t; 5 | using i128 = __int128_t; 6 | struct u256{ 7 | u128 high, low; 8 | static u256 mult(u128 x, u128 y){ 9 | u64 a = x >> 64, b = x; 10 | u64 c = y >> 64, d = y; 11 | u128 ac = (u128)a * c; 12 | u128 ad = (u128)a * d; 13 | u128 bc = (u128)b * c; 14 | u128 bd = (u128)b * d; 15 | u128 carry = (u128)(u64)ad + (u128)(u64)bc + (bd >> 64u); 16 | u128 high = ac + (ad >> 64u) + (bc >> 64u) + (carry >> 64u); 17 | u128 low = (ad << 64u) + (bc << 64u) + bd; 18 | return {high, low}; 19 | } 20 | }; 21 | //x_m := x*r mod n 22 | struct Montgomery{ 23 | u128 mod, inv, r2; 24 | //the N will be an odd number 25 | Montgomery(u128 n) : mod(n), inv(1), r2(-n % n){ 26 | for (int i = 0; i < 7; i++) 27 | inv *= 2 - n * inv; 28 | for (int i = 0; i < 4; i++){ 29 | r2 <<= 1; 30 | if (r2 >= mod) 31 | r2 -= mod; 32 | } 33 | for (int i = 0; i < 5; i++) 34 | r2 = mult(r2, r2); 35 | } 36 | u128 init(u128 x){ 37 | return mult(x, r2); 38 | } 39 | u128 reduce(u256 x){ 40 | u128 q = x.low * inv; 41 | i128 a = x.high - u256::mult(q, mod).high; 42 | if (a < 0) 43 | a += mod; 44 | return a; 45 | } 46 | u128 mult(u128 a, u128 b){ 47 | return reduce(u256::mult(a, b)); 48 | } 49 | }; -------------------------------------------------------------------------------- /test/miscellaneous/scheduling_jobs_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/scheduling_jobs.h" 2 | ll penalty1(vector v){ 3 | ll ans = 0; 4 | ll T=0; 5 | for(Job j: v){ 6 | ans += j.c*(ll)T; 7 | T += j.t; 8 | } 9 | return ans; 10 | } 11 | long double penalty2(vector v){ 12 | long double ans = 0; 13 | ll T=0; 14 | for(Job j: v){ 15 | ans += j.c*exp(alfa*T); 16 | T += j.t; 17 | } 18 | return ans; 19 | } 20 | void testCmp1(){ 21 | srand(2020); 22 | vector v; 23 | for(int i=0; i<9; i++){ 24 | Job j; 25 | j.t = (rand()%1000) + 1; j.c = (rand()%1000) + 1; 26 | v.emplace_back(j); 27 | } 28 | sort(v.begin(), v.end(), cmp1); 29 | ll ans = penalty1(v); 30 | ll mnAns = ans; 31 | do{ 32 | mnAns = min(mnAns, penalty1(v)); 33 | }while(next_permutation(v.begin(), v.end(), cmp1)); 34 | assert(ans == mnAns); 35 | } 36 | void testCmp2(){ 37 | srand(2020); 38 | vector v; 39 | for(int i=0; i<8; i++){ 40 | Job j; 41 | j.t = (rand()%2) + 1; j.c = (rand()%1000) + 1; 42 | v.emplace_back(j); 43 | } 44 | sort(v.begin(), v.end(), cmp2); 45 | long double ans = penalty1(v); 46 | long double mnAns = ans; 47 | do{ 48 | mnAns = min(mnAns, penalty2(v)); 49 | }while(next_permutation(v.begin(), v.end(), cmp1)); 50 | assert(abs(ans-mnAns) < EPS); 51 | } 52 | 53 | int main(){ 54 | testCmp1(); 55 | testCmp2(); 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /test/graph/strongly_connected_component_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/strongly_connected_component.h" 2 | typedef pair pii; 3 | void test1(){ 4 | vector edges; 5 | edges.emplace_back(0, 1); 6 | edges.emplace_back(0, 2); 7 | edges.emplace_back(1, 3); 8 | edges.emplace_back(2, 3); 9 | edges.emplace_back(3, 4); 10 | edges.emplace_back(3, 5); 11 | edges.emplace_back(3, 6); 12 | edges.emplace_back(6, 7); 13 | vector comp = SCC::scc(8, edges); 14 | for (pii p : edges) 15 | assert(comp[p.first] != comp[p.second]); 16 | } 17 | void test2(){ 18 | vector edges; 19 | edges.emplace_back(0, 1); 20 | edges.emplace_back(1, 2); 21 | edges.emplace_back(2, 3); 22 | edges.emplace_back(3, 4); 23 | edges.emplace_back(4, 2); 24 | edges.emplace_back(3, 5); 25 | edges.emplace_back(3, 6); 26 | vector comp = SCC::scc(8, edges); 27 | vector equals = {pii(2, 3), pii(3, 4)}; 28 | vector diff = {pii(0, 1), pii(1, 2), pii(0, 2), pii(3, 5), pii(3, 6), pii(5, 6)}; 29 | for (pii p : equals) 30 | assert(comp[p.first] == comp[p.second]); 31 | for (pii p : diff) 32 | assert(comp[p.first] != comp[p.second]); 33 | } 34 | 35 | void test3(){ 36 | assert(true); // AC: https://cses.fi/problemset/task/1682/ 37 | assert(true); // AC: https://cses.fi/problemset/task/1683/ 38 | assert(true); // AC: https://cses.fi/problemset/task/1686/ 39 | } 40 | 41 | int main(){ 42 | test1(); 43 | test2(); 44 | return 0; 45 | } -------------------------------------------------------------------------------- /code/geometry/convex_polygon.h: -------------------------------------------------------------------------------- 1 | #include "convex_hull.h" 2 | using namespace std; 3 | //Checks if the point P belongs to the segment AB 4 | bool pointInSegment(Point2d &a, Point2d &b, Point2d &p) { 5 | if(!eq(cross(a-p, b-p), 0)) 6 | return false; 7 | return betw(a.x, b.x, p.x) && betw(a.y, b.y, p.y); 8 | } 9 | struct ConvexPolygon{ 10 | vector vp; 11 | ConvexPolygon(vector aux){ 12 | //The points have to be clockwise 13 | vp = convex_hull(aux); 14 | } 15 | //O(log(N)) 16 | //Accepts points on the edge 17 | bool pointInPolygon(Point2d point){ 18 | if(vp.size() < 3) 19 | return pointInSegment(vp[0], vp[1], point); 20 | if(!eq(cross(vp[1]-vp[0], point-vp[0]), 0) and sgn(cross(vp[1]-vp[0], point-vp[0])) != sgn(cross(vp[1]-vp[0], vp.back()-vp[0])) ) 21 | return false; 22 | if(!eq(cross(vp.back()-vp[0], point-vp[0]), 0) and sgn(cross(vp.back()-vp[0], point-vp[0])) != sgn(cross(vp.back() - vp[0], vp[1]-vp[0])) ) 23 | return false; 24 | if(eq(cross(vp[1]-vp[0], point-vp[0]), 0)) 25 | return ge(norm(vp[1]-vp[0]), norm(point-vp[0])); 26 | int pos = 1, l = 1, r = vp.size() - 2; 27 | while(l <= r){ 28 | int mid = (l + r)/2; 29 | if(le(cross(vp[mid] - vp[0], point - vp[0]), 0)){ 30 | pos = mid; 31 | l = mid+1; 32 | }else{ 33 | r = mid-1; 34 | } 35 | } 36 | return pointInTriangle(vp[0], vp[pos], vp[pos+1], point); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /test/strings/suffix_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/strings/suffix_tree.h" 2 | 3 | void test1(){ 4 | SuffixTree::init(); 5 | string s = "paulomiranda"; 6 | SuffixTree::add_string(s); 7 | for(int i=0; i<(int)s.size(); i++){ 8 | for(int j=0; j<(int)s.size(); j++){ 9 | string q = s.substr(i, j-i+1); 10 | assert(SuffixTree::match(q) == true); 11 | } 12 | } 13 | srand(98); 14 | for(int i=0; i<=100; i++){ 15 | string t(5, 'a'); 16 | for(int j=0; j<5; j++) 17 | t[j] = rand()%26; 18 | bool ans = (s.find(t) != -1); 19 | assert(SuffixTree::match(t) == ans); 20 | } 21 | } 22 | 23 | void test2(){ 24 | SuffixTree::init(); 25 | string s = "paulomiranda"; 26 | string s1 = "paulo", s2 ="miranda"; 27 | SuffixTree::add_string(s1); 28 | SuffixTree::add_string(s2); 29 | for(int i=0; i<(int)s.size(); i++){ 30 | for(int j=0; j<(int)s.size(); j++){ 31 | string q = s.substr(i, j-i+1); 32 | bool ans = false; 33 | ans |= (s1.find(q) != -1); 34 | ans |= (s2.find(q) != -1); 35 | assert(SuffixTree::match(q) == ans); 36 | } 37 | } 38 | srand(98); 39 | for(int i=0; i<=100; i++){ 40 | string t(5, 'a'); 41 | for(int j=0; j<5; j++) 42 | t[j] = rand()%26; 43 | bool ans = false; 44 | ans |= (s1.find(t) != -1); 45 | ans |= (s2.find(t) != -1); 46 | assert(SuffixTree::match(t) == ans); 47 | } 48 | } 49 | 50 | int main() { 51 | test1(); 52 | test2(); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /code/graph/graph_theorem.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define all(x) x.begin(),x.end() 3 | using namespace std; 4 | using ll = long long; 5 | using pii = pair; 6 | namespace GraphTheorem{ 7 | // return if a sequence of integers d can be represented as the 8 | // degree sequence of a finite simple graph on n vertices 9 | bool ErdosGallai(vector d){ 10 | int n = d.size(); 11 | sort(all(d), greater()); 12 | ll sum1 = 0, sum2 = 0; 13 | int mn = n-1; 14 | for(int k=1; k<=n; k++){ 15 | sum1 += d[k-1]; 16 | while(k <= mn and k > d[mn]) 17 | sum2 += d[mn--]; 18 | if(mn + 1 < k) 19 | sum2 -= d[mn++]; 20 | ll a = sum1, b = k*(ll)mn + sum2; 21 | if(a > b) 22 | return false; 23 | } 24 | return sum1%2 == 0; 25 | } 26 | vector recoverErdosGallai(vector d){ 27 | int n = d.size(); 28 | priority_queue pq; 29 | for(int i=0; i edges; 32 | while(!pq.empty()){ 33 | auto [g, u] = pq.top(); 34 | pq.pop(); 35 | vector aux(g); 36 | for(int i=0; i 2 | using namespace std; 3 | // "abcabcd" is [0,0,0,1,2,3,0] 4 | // "aabaaab" is [0,1,0,1,2,2,3] 5 | vector kmp(string s) { 6 | int n = (int)s.length(); 7 | // pi[i] is the length of the longest proper prefix of the substring 8 | // s[0..i] which is also a suffix of this substring. 9 | vector pi(n); 10 | for (int i = 1; i < n; i++) { 11 | int j = pi[i-1]; 12 | while (j > 0 and s[i] != s[j]) 13 | j = pi[j-1]; 14 | if (s[i] == s[j]) 15 | j++; 16 | pi[i] = j; 17 | } 18 | return pi; 19 | } 20 | //The ans[i] count the amount of occurrence of the prefix s[0..i] in s 21 | vector prefixOccurrences(string &s){ 22 | auto pi = kmp(s); 23 | int n = pi.size(); 24 | vector ans(n + 1); 25 | for (int i = 0; i < n; i++) 26 | ans[pi[i]]++; 27 | for (int i = n-1; i > 0; i--) 28 | ans[pi[i-1]] += ans[i]; 29 | for (int i = 1; i <= n; i++) 30 | ans[i-1] = ans[i] + 1; 31 | ans.pop_back(); 32 | return ans; 33 | } 34 | int K = 26; 35 | inline int getID(char c){ 36 | return c-'a'; 37 | } 38 | vector> computeAutomaton(string s) { 39 | s += '#'; 40 | int n = s.size(); 41 | vector pi = kmp(s); 42 | vector> aut(n, vector(26)); 43 | for(int i = 0; i < n; i++){ 44 | for(int c = 0; c < K; c++){ 45 | if(i > 0 and c != getID(s[i])) 46 | aut[i][c] = aut[pi[i-1]][c]; 47 | else 48 | aut[i][c] = i + (c == getID(s[i])); 49 | } 50 | } 51 | return aut; 52 | } -------------------------------------------------------------------------------- /code/math/prime.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "basic_math.h" 3 | using namespace std; 4 | typedef unsigned long long ull; 5 | ull modMul(ull a, ull b, ull mod){ 6 | return (a * (__uint128_t)b) % mod; 7 | } 8 | bool checkComposite(ull n, ull a, ull d, int s){ 9 | ull x = fastPow(a, d, n); 10 | if (x == 1 or x == n - 1) 11 | return false; 12 | for (int r = 1; r < s; r++){ 13 | x = modMul(x, x, n); 14 | if (x == n - 1LL) 15 | return false; 16 | } 17 | return true; 18 | }; 19 | bool millerRabin(ull n){ 20 | if (n < 2) 21 | return false; 22 | int r = 0; 23 | ull d = n - 1LL; 24 | while ((d & 1LL) == 0){ 25 | d >>= 1; 26 | r++; 27 | } 28 | for (ull a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}){ 29 | if (n == a) 30 | return true; 31 | if (checkComposite(n, a, d, r)) 32 | return false; 33 | } 34 | return true; 35 | } 36 | ull pollard(ull n){ 37 | auto f = [n](ull x) { return modMul(x, x, n) + 1; }; 38 | ull x = 0, y = 0, t = 0, prd = 2, i = 1, q; 39 | while (t++ % 40 || __gcd(prd, n) == 1){ 40 | if (x == y) 41 | x = ++i, y = f(x); 42 | if ((q = modMul(prd, max(x, y) - min(x, y), n))) 43 | prd = q; 44 | x = f(x), y = f(f(y)); 45 | } 46 | return __gcd(prd, n); 47 | } 48 | vector factor(ull n){ 49 | if (n == 1) 50 | return {}; 51 | if (millerRabin(n)) 52 | return {n}; 53 | ull x = pollard(n); 54 | auto l = factor(x), r = factor(n / x); 55 | l.insert(l.end(), r.begin(), r.end()); 56 | return l; 57 | } -------------------------------------------------------------------------------- /test/graph/lct_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/lct.h" 2 | 3 | int dad[10010]; 4 | void init(int n){ 5 | for(int i=0; i v1(1, -1), v2(1, -2); 10 | while(dad[a] != -1){ 11 | v1.push_back(a); 12 | a = dad[a]; 13 | } 14 | v1.push_back(a); 15 | while(dad[b] != -1){ 16 | v2.push_back(b); 17 | b = dad[b]; 18 | } 19 | v2.push_back(b); 20 | reverse(v1.begin(), v1.end()); 21 | reverse(v2.begin(), v2.end()); 22 | int last = -1; 23 | for(int i=0; ;i++){ 24 | if(v1[i] == v2[i]) 25 | last = v1[i]; 26 | else 27 | break; 28 | } 29 | 30 | return last; 31 | } 32 | int findRoot(int x){ 33 | if(dad[x] == -1) 34 | return x; 35 | return findRoot(dad[x]); 36 | } 37 | void test(){ 38 | srand(2020); 39 | int n=10000, q = 10010; 40 | 41 | LCT::init(n); 42 | init(n); 43 | while(q--){ 44 | int op = rand()%4; 45 | if(op == 0){ 46 | int x = rand()%n; 47 | assert(LCT::findRoot(x) == findRoot(x)); 48 | }else if(op == 1){ 49 | int x = LCT::findRoot(rand()%n), y = rand()%n; 50 | if(LCT::findRoot(y) == x) 51 | continue; 52 | LCT::link(x, y); 53 | dad[x] = y; 54 | }else if(op == 2){ 55 | int x = rand()%n; 56 | dad[x] = -1; 57 | LCT::cut(x); 58 | }else{ 59 | int x = rand()%n, y = rand()%n; 60 | assert(LCT::lca(x, y) == lca(x, y)); 61 | } 62 | } 63 | } 64 | int main() { 65 | test(); 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /test/data_structures/wavelet_tree_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/wavelet_tree.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 100; 4 | int v[MAXN + 10]; 5 | int cp[MAXN + 10]; 6 | 7 | int randWithNeg(){ 8 | if (rand() % 2) 9 | return (rand() % MAXX); 10 | else 11 | return -(rand() % MAXX); 12 | } 13 | 14 | int lte(int a, int b, int k){ 15 | int count = 0; 16 | for (int i = a; i <= b; i++) 17 | count += v[i] <= k; 18 | return count; 19 | } 20 | 21 | int count(int a, int b, int k){ 22 | int count = 0; 23 | for (int i = a; i <= b; i++) 24 | count += v[i] == k; 25 | return count; 26 | } 27 | 28 | int kth(int a, int b, int k){ 29 | vector v2(b - a + 1); 30 | int count = 0; 31 | for (int i = a; i <= b; i++) 32 | v2[i - a] = v[i]; 33 | sort(v2.begin(), v2.end()); 34 | return v2[k - 1]; 35 | } 36 | 37 | void testQuery(){ 38 | srand(42); 39 | for (int i = 1; i <= MAXN; i++){ 40 | v[i] = randWithNeg(); 41 | cp[i] = v[i]; 42 | } 43 | 44 | WaveletTree::init(cp + 1, cp + MAXN + 1, -MAXX, MAXX); 45 | for (int i = 1; i <= MAXN; i++){ 46 | for (int j = i; j <= MAXN; j++){ 47 | for (int k = 1; k <= (j - i + 1); k++){ 48 | assert(WaveletTree::lte(i, j, v[i + k - 1]) == lte(i, j, v[i + k - 1])); 49 | assert(WaveletTree::kth(i, j, k) == kth(i, j, k)); 50 | assert(WaveletTree::count(i, j, v[i + k - 1]) == count(i, j, v[i + k - 1])); 51 | } 52 | } 53 | } 54 | } 55 | 56 | int main(){ 57 | testQuery(); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /code/math/catalan.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | const int MOD = 1000000007; 4 | typedef long long ll; 5 | ll extGcd(ll a, ll b, ll &x, ll &y){ 6 | if (b == 0){ 7 | x = 1, y = 0; 8 | return a; 9 | }else{ 10 | ll g = extGcd(b, a % b, y, x); 11 | y -= (a / b) * x; 12 | return g; 13 | } 14 | } 15 | ll inv(ll a){ 16 | ll inv_x, y; 17 | extGcd(a, MOD, inv_x, y); 18 | return (inv_x%MOD + MOD)%MOD; 19 | } 20 | const int MAXN = 4000010; 21 | ll fat[MAXN], ifat[MAXN]; 22 | void init(){ 23 | fat[0] = 1; 24 | for(int i=1; i=0; i--) 28 | ifat[i] = (ifat[i+1]*(i+1))%MOD; 29 | assert(ifat[0] == 1); 30 | } 31 | ll C(int n, int k){ 32 | if(k > n) 33 | return 0; 34 | return (fat[n]*((ifat[k]*ifat[n-k])%MOD))%MOD; 35 | } 36 | ll catalan(int n){ 37 | return (C(2*n, n) - C(2*n, n-1) + MOD)%MOD; 38 | } 39 | ll f(int x1, int y1, int x2, int y2){ 40 | int y = y2 - y1, x = x2 - x1; 41 | if(y < 0 or x < 0) 42 | return 0; 43 | return C(x + y, x); 44 | } 45 | // o = number of '(', c = number of ')', k = fixed prefix of '(' extra 46 | // Catalan Generalization, open[i] >= close[i] for each 0 <= i < o + c + k 47 | // where open[i] is number of '(' in prefix until i 48 | // and close[i] is number of ')' 49 | ll catalan2(int o, int c, int k){ 50 | int x = o + k - c; 51 | if(x < 0) 52 | return 0; 53 | return (f(k, 0, o+k, c) - f(k, 0, o+k-x-1, c + x + 1) + MOD)%MOD; 54 | } -------------------------------------------------------------------------------- /code/data_structures/query_tree.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef pair Query; // Anything that can be activated for a period of time 4 | int n; 5 | int getAnswer(); 6 | void rollback(int t); 7 | void insert(Query q); 8 | int getLastVersion(); 9 | namespace QueryTree{ 10 | const int MAXN = 200010; 11 | vector queries[4*MAXN]; 12 | int T; 13 | void addQuery(int node, int i, int j, int a, int b, Query &q){ 14 | if ((i > b) or (j < a)) 15 | return; 16 | if (a <= i and j <= b){ 17 | queries[node].push_back(q); 18 | return; 19 | } 20 | int m = (i + j) / 2; 21 | int l = (node << 1); 22 | int r = l + 1; 23 | addQuery(l, i, m, a, b, q); 24 | addQuery(r, m + 1, j, a, b, q); 25 | } 26 | void dfs(int node, int i, int j, vector &ans){ 27 | int lastTime = getLastVersion(); 28 | for(Query q: queries[node]) 29 | insert(q); 30 | if( i == j){ 31 | ans[i] = getAnswer(); 32 | }else{ 33 | int m = (i + j) / 2; 34 | int l = (node << 1); 35 | int r = l + 1; 36 | dfs(l, i, m, ans); 37 | dfs(r, m + 1, j, ans); 38 | } 39 | rollback(lastTime); 40 | } 41 | // Public: 42 | void init(int tMax){ 43 | T = tMax; 44 | for(int i=0; i<=T; i++) 45 | queries[i].clear(); 46 | } 47 | void addQuery(int l, int r, Query q){ 48 | addQuery(1, 0, T, l, r, q); 49 | } 50 | vector solve(){ 51 | vector ans(T+1); 52 | dfs(1, 0, T, ans); 53 | return ans; 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /code/data_structures/segment_tree_2d.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | struct SegTree2D{ 4 | private: 5 | int n, m; 6 | typedef int Node; 7 | Node neutral = -0x3f3f3f3f; 8 | vector> seg; 9 | Node join(Node a, Node b){ 10 | return max(a, b); 11 | } 12 | public: 13 | SegTree2D(int n1, int m1){ 14 | n = n1, m = m1; 15 | seg.assign(2 * n, vector(2 * m, 0)); 16 | } 17 | void update(int x, int y, int val){ 18 | assert(0 <= x && x < n && 0 <= y && y < m); 19 | x += n, y += m; 20 | seg[x][y] = val; 21 | for (int j = y / 2; j > 0; j /= 2) 22 | seg[x][j] = join(seg[x][2 * j], seg[x][2 * j + 1]); 23 | for (x /= 2; x > 0; x /= 2){ 24 | seg[x][y] = join(seg[2 * x][y], seg[2 * x + 1][y]); 25 | for (int j = y / 2; j > 0; j /= 2){ 26 | seg[x][j] = join(seg[x][2 * j], seg[x][2 * j + 1]); 27 | } 28 | } 29 | } 30 | vector getCover(int l, int r, int N){ 31 | l = std::max(0, l); 32 | r = std::min(N, r); 33 | vector ans; 34 | for (l += N, r += N; l < r; l /= 2, r /= 2){ 35 | if (l & 1) 36 | ans.push_back(l++); 37 | if (r & 1) 38 | ans.push_back(--r); 39 | } 40 | return ans; 41 | } 42 | Node query(int x1, int y1, int x2, int y2){ 43 | auto c1 = getCover(x1, x2 + 1, n); 44 | auto c2 = getCover(y1, y2 + 1, m); 45 | Node ans = neutral; 46 | for (auto i : c1){ 47 | for (auto j : c2){ 48 | ans = join(ans, seg[i][j]); 49 | } 50 | } 51 | return ans; 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /test/graph/tree_id_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/graph/tree_id.h" 2 | void test1(){ 3 | vector t1; 4 | t1.emplace_back(1, 2); 5 | t1.emplace_back(3, 2); 6 | t1.emplace_back(4, 2); 7 | t1.emplace_back(2, 0); 8 | 9 | vector t2; 10 | t2.emplace_back(0, 3); 11 | t2.emplace_back(2, 3); 12 | t2.emplace_back(4, 3); 13 | t2.emplace_back(3, 1); 14 | auto id1 = TreeID::getTreeID(t1, 5); 15 | auto id2 = TreeID::getTreeID(t2, 5); 16 | assert(id1 == id2); 17 | } 18 | 19 | void test2(){ 20 | vector t1; 21 | t1.emplace_back(1, 3); 22 | t1.emplace_back(3, 2); 23 | t1.emplace_back(4, 2); 24 | t1.emplace_back(2, 0); 25 | 26 | vector t2; 27 | t2.emplace_back(0, 3); 28 | t2.emplace_back(2, 3); 29 | t2.emplace_back(4, 3); 30 | t2.emplace_back(3, 1); 31 | auto id1 = TreeID::getTreeID(t1, 5); 32 | auto id2 = TreeID::getTreeID(t2, 5); 33 | assert(id1 != id2); 34 | } 35 | void test3(){ // AC: https://www.urionlinejudge.com.br/judge/pt/problems/view/1229 36 | ios_base::sync_with_stdio(false); cin.tie(NULL); 37 | int n; 38 | while(cin >> n){ 39 | vector t1, t2; 40 | for(int i=0; i> a >> b; a--; b--; 43 | t1.emplace_back(a, b); 44 | } 45 | for(int i=0; i> a >> b; a--; b--; 48 | t2.emplace_back(a, b); 49 | } 50 | if(TreeID::isomorphic(t1, t2, n)) 51 | cout << "S" << endl; 52 | else 53 | cout << "N" << endl; 54 | } 55 | } 56 | int main(){ 57 | test1(); 58 | test2(); 59 | // test3(); 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /code/data_structures/segment_tree_iterative.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class SegTreeIterative{ 4 | private: 5 | typedef long long Node; 6 | Node neutral = 0; 7 | vector st; 8 | int n; 9 | inline Node join(Node a, Node b){ 10 | return a + b; 11 | } 12 | public: 13 | template 14 | SegTreeIterative(MyIterator begin, MyIterator end){ 15 | int sz = end - begin; 16 | for (n = 1; n < sz; n <<= 1); 17 | st.assign(n << 1, neutral); 18 | for (int i = 0; i < sz; i++, begin++) 19 | st[i + n] = (*begin); 20 | for (int i = n - 1; i; i--){ 21 | st[i] = join(st[(i << 1)], st[(i << 1) + 1]); 22 | } 23 | } 24 | //0-indexed 25 | void update(int i, Node x){ 26 | st[i += n] = x; 27 | for (i >>= 1; i; i >>= 1) 28 | st[i] = join(st[i << 1], st[(i << 1) + 1]); 29 | } 30 | //0-indexed [l, r] 31 | Node query(int l, int r){ 32 | Node ansL = neutral, ansR = neutral; 33 | for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1){ 34 | if (l & 1) 35 | ansL = join(ansL, st[l++]); 36 | if (r & 1) 37 | ansR = join(st[--r], ansR); 38 | } 39 | return join(ansL, ansR); 40 | } 41 | Node lower_bound(int k){ 42 | int no=1, l=0, r=n-1; 43 | while(l>1; 45 | int lo = no<<1; 46 | if(st[lo] >= k){ 47 | no = lo; 48 | r = mid; 49 | }else{ 50 | k -= st[lo]; 51 | no = lo + 1; 52 | l = mid + 1; 53 | } 54 | } 55 | if(st[no] >= k) 56 | return l; 57 | else 58 | return -1; 59 | } 60 | }; -------------------------------------------------------------------------------- /code/graph/mincut.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | typedef long long ll; 4 | //This algorithm finds the Global Min-Cut in O(|V|^3) 5 | namespace MinCut{ 6 | const int MAXN = 510; 7 | bool exist[MAXN], in_a[MAXN]; 8 | ll g[MAXN][MAXN], w[MAXN]; 9 | vector v[MAXN]; 10 | int n; 11 | void init(int n1){ 12 | n = n1; 13 | memset(g, 0, sizeof(g)); 14 | } 15 | void addEdge(int a, int b, int w1){ 16 | if(a == b) return; 17 | g[a][b] += w1; 18 | g[b][a] += w1; 19 | } 20 | pair> mincut() { 21 | ll best_cost = 0x3f3f3f3f3f3f3f3fLL; 22 | vector best_cut; 23 | for (int i=0; i w[sel])) 33 | sel = i; 34 | if(it == n-ph-1){ 35 | if(w[sel] < best_cost) 36 | best_cost = w[sel], best_cut = v[sel]; 37 | v[prev].insert (v[prev].end(), v[sel].begin(), v[sel].end()); 38 | for(int i=0; i 3 | #include 4 | using namespace __gnu_pbds; 5 | 6 | typedef tree, rb_tree_tag, tree_order_statistics_node_update> ordered_set; 7 | 8 | const int MAXX = 1000000000; 9 | const int MAXOP = 100000; 10 | enum op{ 11 | INSERT = 0, 12 | ERASE = 1, 13 | COUNT = 2, 14 | NTH = 3 15 | }; 16 | 17 | int randWithNeg(){ 18 | if (rand() % 2) 19 | return (rand() % MAXX); 20 | else 21 | return -(rand() % MAXX); 22 | } 23 | 24 | void testTreap(){ 25 | ordered_set st; 26 | Treap::init(); 27 | int prev = 0; 28 | for (int k = 0; k < MAXOP; k++){ 29 | int op = rand() % 4; 30 | if (op == INSERT){ 31 | int x = randWithNeg(); 32 | st.insert(x); 33 | if (Treap::count(x) == 0) 34 | Treap::insert(x); 35 | prev = x; 36 | }else if (op == ERASE){ 37 | int x = randWithNeg(); 38 | st.erase(x); 39 | Treap::erase(x); 40 | st.erase(prev); 41 | Treap::erase(prev); 42 | }else if (op == COUNT){ 43 | int x = randWithNeg(); 44 | assert((st.find(x) != st.end()) == (Treap::count(x) != 0)); 45 | assert((st.find(prev) != st.end()) == (Treap::count(prev) != 0)); 46 | }else if (op == NTH){ 47 | if (st.size() == 0) 48 | continue; 49 | int x = rand() % st.size(); 50 | assert((*st.find_by_order(x)) == Treap::nth(x)); 51 | } 52 | assert((int)st.size() == Treap::size()); 53 | } 54 | } 55 | 56 | int main(){ 57 | testTreap(); 58 | return 0; 59 | } -------------------------------------------------------------------------------- /test/miscellaneous/kadane_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/miscellaneous/kadane.h" 2 | void test1(){ 3 | int T = 5; 4 | srand(2020); 5 | while(T--){ 6 | int n = 1010; 7 | vector v(n); 8 | for(int i=0; i> mat(n, vector(m)); 38 | for(int i=0; i 2 | using namespace std; 3 | 4 | typedef int f_type; 5 | struct Node{ 6 | f_type value; 7 | Node *l, *r; 8 | Node(f_type x = 0): value(x){ 9 | l = r = nullptr; 10 | } 11 | }; 12 | inline bool heapMin(f_type a, f_type b){ 13 | return a > b; 14 | } 15 | inline bool heapMax(f_type a, f_type b){ 16 | return a < b; 17 | } 18 | struct RandomizedHeap{ 19 | Node *root; 20 | int sz; 21 | RandomizedHeap(){ 22 | srand(time(NULL)); 23 | root = nullptr; 24 | sz = 0; 25 | } 26 | void rdFree(Node *n){ 27 | if(n == nullptr) return; 28 | rdFree(n->l); rdFree(n->r); 29 | delete n; 30 | } 31 | ~RandomizedHeap(){ 32 | rdFree(root); 33 | } 34 | Node* merge(Node *t1, Node *t2) { 35 | if(!t1 || !t2) 36 | return t1 ? t1 : t2; 37 | if(heapMin(t1->value, t2->value)) 38 | swap(t1, t2); 39 | if(rand() & 1) 40 | swap(t1->l, t1->r); 41 | t1->l = merge(t1->l, t2); 42 | return t1; 43 | } 44 | //Can be performed in O(logn) on average. 45 | void merge(RandomizedHeap &oth){ 46 | root = merge(root, oth.root); 47 | sz += oth.sz; 48 | oth.root = nullptr; 49 | } 50 | int top(){ 51 | return (root != nullptr) ? root->value : 0; 52 | } 53 | void pop(){ 54 | if(root == nullptr) return; 55 | Node *l = root->l; 56 | Node *r = root->r; 57 | delete root; 58 | root = merge(l, r); 59 | sz--; 60 | } 61 | void push(int x){ 62 | Node *nw = new Node(x); 63 | root = merge(root, nw); 64 | sz++; 65 | } 66 | int size(){ 67 | return sz; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /test/data_structures/segment_tree_iterative_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/segment_tree_iterative.h" 2 | const int MAXX = 1000000000; 3 | const int MAXN = 1000; 4 | int v[MAXN + 10]; 5 | 6 | int randWithNeg(){ 7 | if (rand() % 2) 8 | return (rand() % MAXX); 9 | else 10 | return -(rand() % MAXX); 11 | } 12 | 13 | long long rangeSum(int a, int b){ 14 | long long ans = v[a]; 15 | for (int i = a + 1; i <= b; i++) 16 | ans = (ans + v[i]); 17 | return ans; 18 | } 19 | 20 | void testUpdateAndQuery(){ 21 | srand(42); 22 | for (int i = 0; i < MAXN; i++){ 23 | v[i] = randWithNeg(); 24 | } 25 | 26 | SegTreeIterative st(v, v + MAXN); 27 | for (int i = 0; i < MAXN; i++){ 28 | for (int j = i; j < MAXN; j++){ 29 | assert(st.query(i, j) == rangeSum(i, j)); 30 | } 31 | } 32 | for (int i = 0; i < MAXN; i++){ 33 | for (int j = i; j < MAXN; j++){ 34 | assert(st.query(i, j) == rangeSum(i, j)); 35 | v[j] = randWithNeg(); 36 | st.update(j, v[j]); 37 | assert(st.query(i, j) == rangeSum(i, j)); 38 | } 39 | } 40 | } 41 | 42 | void testLowerBound(){ 43 | srand(42); 44 | for (int i = 0; i < MAXN; i++){ 45 | v[i] = rand()%5; 46 | } 47 | 48 | SegTreeIterative st(v, v + MAXN); 49 | for (int i = 0; i < MAXN; i++){ 50 | int k = rand()%MAXN; 51 | int ans = -1; 52 | for(int j=0; j < MAXN; j++){ 53 | if(st.query(0, j) >= k){ 54 | ans = j; 55 | break; 56 | } 57 | } 58 | assert(st.lower_bound(k) == ans); 59 | } 60 | } 61 | 62 | int main(){ 63 | testUpdateAndQuery(); 64 | testLowerBound(); 65 | return 0; 66 | } -------------------------------------------------------------------------------- /code/data_structures/segment_tree.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | class SegTree{ 4 | private: 5 | typedef long long Node; 6 | Node neutral = 0; 7 | vector st; 8 | vector v; 9 | int n; 10 | Node join(Node a, Node b){ 11 | return (a + b); 12 | } 13 | void build(int node, int i, int j){ 14 | if (i == j){ 15 | st[node] = v[i]; 16 | return; 17 | } 18 | int m = (i + j) / 2; 19 | int l = (node << 1); 20 | int r = l + 1; 21 | build(l, i, m); 22 | build(r, m + 1, j); 23 | st[node] = join(st[l], st[r]); 24 | } 25 | Node query(int node, int i, int j, int a, int b){ 26 | if ((i > b) or (j < a)) 27 | return neutral; 28 | if ((a <= i) and (j <= b)) 29 | return st[node]; 30 | int m = (i + j) / 2; 31 | int l = (node << 1); 32 | int r = l + 1; 33 | return join(query(l, i, m, a, b), query(r, m + 1, j, a, b)); 34 | } 35 | void update(int node, int i, int j, int idx, Node value){ 36 | if (i == j){ 37 | st[node] = value; 38 | return; 39 | } 40 | int m = (i + j) / 2; 41 | int l = (node << 1); 42 | int r = l + 1; 43 | if (idx <= m) 44 | update(l, i, m, idx, value); 45 | else 46 | update(r, m + 1, j, idx, value); 47 | st[node] = join(st[l], st[r]); 48 | } 49 | public: 50 | template 51 | SegTree(MyIterator begin, MyIterator end){ 52 | n = end - begin; 53 | v = vector(begin, end); 54 | st.resize(4 * n + 5); 55 | build(1, 0, n - 1); 56 | } 57 | //0-indexed [a, b] 58 | Node query(int a, int b){ 59 | return query(1, 0, n - 1, a, b); 60 | } 61 | //0-indexed 62 | void update(int idx, int value){ 63 | update(1, 0, n - 1, idx, value); 64 | } 65 | }; -------------------------------------------------------------------------------- /test/data_structures/implicit_treap_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/data_structures/implicit_treap.h" 2 | 3 | void testInsert(){ 4 | ITreap::init(); 5 | ITreap::insert(0, 10); 6 | ITreap::insert(1, 20); 7 | ITreap::insert(2, 30); 8 | ITreap::insert(1, 5); 9 | 10 | assert(ITreap::nth(0) == 10); 11 | assert(ITreap::nth(1) == 5); 12 | assert(ITreap::nth(2) == 20); 13 | assert(ITreap::nth(3) == 30); 14 | } 15 | 16 | void testErase(){ 17 | ITreap::init(); 18 | ITreap::insert(0, 10); 19 | ITreap::insert(1, 5); 20 | ITreap::insert(2, 20); 21 | ITreap::insert(3, 30); 22 | 23 | ITreap::erase(2); 24 | 25 | assert(ITreap::nth(0) == 10); 26 | assert(ITreap::nth(1) == 5); 27 | assert(ITreap::nth(2) == 30); 28 | } 29 | 30 | void testQuery(){ 31 | ITreap::init(); 32 | ITreap::insert(0, 10); 33 | ITreap::insert(1, 20); 34 | ITreap::insert(2, 30); 35 | ITreap::insert(3, 5); 36 | 37 | assert(ITreap::query(0, 2) == 60); 38 | assert(ITreap::query(1, 1) == 20); 39 | assert(ITreap::query(2, 3) == 35); 40 | } 41 | 42 | void testReverse(){ 43 | ITreap::init(); 44 | ITreap::insert(0, 10); 45 | ITreap::insert(1, 20); 46 | ITreap::insert(2, 30); 47 | ITreap::insert(3, 5); 48 | 49 | ITreap::reverse(1, 3); 50 | 51 | assert(ITreap::nth(0) == 10); 52 | assert(ITreap::nth(1) == 5); 53 | assert(ITreap::nth(2) == 30); 54 | assert(ITreap::nth(3) == 20); 55 | 56 | ITreap::reverse(1, 2); 57 | 58 | assert(ITreap::nth(0) == 10); 59 | assert(ITreap::nth(1) == 30); 60 | assert(ITreap::nth(2) == 5); 61 | assert(ITreap::nth(3) == 20); 62 | } 63 | 64 | int main(){ 65 | testInsert(); 66 | testErase(); 67 | testQuery(); 68 | testReverse(); 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /test/math/binomial_coefficients_test.cpp: -------------------------------------------------------------------------------- 1 | #include "../../code/math/binomial_coefficients.h" 2 | vector primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89}; 3 | 4 | void testC1(){ 5 | vector factorial(21); 6 | factorial[0] = factorial[1] = 1; 7 | for (int n = 2; n <= 20; n++) 8 | factorial[n] = n * factorial[n - 1]; 9 | for (int n = 0; n <= 20; n++){ 10 | for (int k = 0; k <= n; k++){ 11 | ll comb = (factorial[n] / factorial[k]) / factorial[n - k]; 12 | assert(comb == C1(n, k)); 13 | } 14 | } 15 | } 16 | 17 | void testC2(){ 18 | vector factorial(21); 19 | factorial[0] = factorial[1] = 1; 20 | for (int n = 2; n <= 20; n++) 21 | factorial[n] = n * factorial[n - 1]; 22 | 23 | for (int mod : primes){ 24 | auto comb = C2(20, mod); 25 | for (int n = 0; n <= 20; n++){ 26 | for (int k = 0; k <= n; k++){ 27 | ll ans = (factorial[n] / factorial[k]) / factorial[n - k]; 28 | assert(ans % mod == comb[n][k]); 29 | } 30 | } 31 | } 32 | } 33 | 34 | void testC3(){ 35 | for (int mod : primes){ 36 | auto comb = C2(mod - 1, mod); 37 | prevC3(mod - 1, mod); 38 | for (int n = 0; n < mod; n++){ 39 | for (int k = 0; k <= n; k++){ 40 | assert(comb[n][k] == C3(n, k, mod)); 41 | } 42 | } 43 | } 44 | } 45 | 46 | void testC4(){ 47 | for (int mod : primes){ 48 | auto comb = C2(mod - 1, mod); 49 | for (int n = 0; n < mod; n++){ 50 | for (int k = 0; k <= n; k++){ 51 | assert(comb[n][k] == C4(n, k, mod)); 52 | } 53 | } 54 | } 55 | } 56 | 57 | int main(){ 58 | testC1(); 59 | testC2(); 60 | testC3(); 61 | testC4(); 62 | return 0; 63 | } -------------------------------------------------------------------------------- /code/miscellaneous/mo_with_update.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define all(x) x.begin(),x.end() 3 | using namespace std; 4 | using pii = pair; 5 | const int INF = 0x3f3f3f3f; 6 | const int BLOCK_SIZE = 2800; // (2*N^2)^(1/3) 7 | const int MAXN = 100010; 8 | int v[MAXN]; 9 | void remove(int x); 10 | void add(int x); 11 | void clearAnswer(); 12 | int getAnswer(); 13 | struct Query{ 14 | int l, r, t; 15 | bool operator<(const Query &oth) const{ 16 | if (l / BLOCK_SIZE != oth.l / BLOCK_SIZE) 17 | return l < oth.l; 18 | if (r / BLOCK_SIZE != oth.r / BLOCK_SIZE) 19 | return r < oth.r; 20 | return t < oth.t; 21 | } 22 | }; 23 | struct Update{ 24 | int pos, newV, oldV, t; 25 | }; 26 | //O(Q * N^(2/3)): N=10^5 -> 1.5s 27 | vector mo_s_algorithm(vector vq, vector vu){ 28 | vector answers; 29 | sort(all(vq)); 30 | clearAnswer(); 31 | int L = 0, R = 0, T = 0, szT = vu.size(); 32 | add(v[0]); 33 | for(Query q : vq){ 34 | while(q.l < L) add(v[--L]); 35 | while(R < q.r) add(v[++R]); 36 | while(L < q.l) remove(v[L++]); 37 | while(q.r < R) remove(v[R--]); 38 | while(T < szT and vu[T].t <= q.t){ 39 | Update &u = vu[T++]; 40 | if(L <= u.pos and u.pos <= R){ 41 | remove(u.oldV); 42 | add(u.newV); 43 | } 44 | v[u.pos] = u.newV; 45 | } 46 | while(T > 0 and vu[T-1].t > q.t){ 47 | Update &u = vu[--T]; 48 | if(L <= u.pos and u.pos <= R){ 49 | remove(u.newV); 50 | add(u.oldV); 51 | } 52 | v[u.pos] = u.oldV; 53 | } 54 | answers.emplace_back(q.t, getAnswer()); 55 | } 56 | sort(all(answers)); 57 | vector ret; 58 | for(auto [t, x]: answers) 59 | ret.push_back(x); 60 | return ret; 61 | } -------------------------------------------------------------------------------- /code/data_structures/merge_sort_tree.h: -------------------------------------------------------------------------------- 1 | #include 2 | #define all(x) x.begin(),x.end() 3 | using namespace std; 4 | class MergeSortTree{ 5 | private: 6 | typedef vector Node; 7 | Node neutral; 8 | vector st; 9 | int n; 10 | inline void join(Node &a, Node &b, Node &ans){ 11 | ans.resize(a.size() + b.size()); 12 | merge(all(a), all(b), ans.begin()); 13 | } 14 | inline int szEq(int node, int k){ 15 | return upper_bound(all(st[node]), k) - lower_bound(all(st[node]), k); 16 | } 17 | inline int szLt(int node, int k){ 18 | return lower_bound(all(st[node]), k) - st[node].begin(); 19 | } 20 | public: 21 | template 22 | MergeSortTree(MyIterator begin, MyIterator end){ 23 | int sz = end - begin; 24 | for (n = 1; n < sz; n <<= 1); 25 | st.assign(n << 1, neutral); 26 | for (int i = 0; i < sz; i++, begin++) 27 | st[i + n].assign(1, *begin); 28 | for (int i = n - 1; i; i--){ 29 | int l = (i << 1); 30 | join(st[l], st[l+1], st[i]); 31 | } 32 | } 33 | // 0-indexed 34 | // Counts the number of elements less than k in the range [L..R] 35 | int lt(int l, int r, int k){ 36 | int ans = 0; 37 | for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1){ 38 | if (l & 1) 39 | ans += szLt(l++, k); 40 | if (r & 1) 41 | ans += szLt(--r, k); 42 | } 43 | return ans; 44 | } 45 | // 0-indexed 46 | // Counts the number of elements equal to k in the range [L..R] 47 | int eq(int l, int r, int k){ 48 | int ans = 0; 49 | for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1){ 50 | if (l & 1) 51 | ans += szEq(l++, k); 52 | if (r & 1) 53 | ans += szEq(--r, k); 54 | } 55 | return ans; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /code/data_structures/segment_tree_persistent.h: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | namespace PerSegTree{ 4 | const int MAX = 2e5 + 10, UPD = 2e5 + 10, LOG = 20; 5 | const int MAXS = 4 * MAX + UPD * LOG; 6 | typedef long long pst_t; 7 | pst_t seg[MAXS]; 8 | int T[UPD], L[MAXS], R[MAXS], cnt, t; 9 | int n, *v; 10 | pst_t neutral = 0; 11 | pst_t join(pst_t a, pst_t b){ 12 | return a + b; 13 | } 14 | pst_t build(int p, int l, int r){ 15 | if (l == r) 16 | return seg[p] = v[l]; 17 | L[p] = cnt++, R[p] = cnt++; 18 | int m = (l + r) / 2; 19 | return seg[p] = join(build(L[p], l, m), build(R[p], m + 1, r)); 20 | } 21 | pst_t query(int a, int b, int p, int l, int r){ 22 | if (b < l or r < a) 23 | return neutral; 24 | if (a <= l and r <= b) 25 | return seg[p]; 26 | int m = (l + r) / 2; 27 | return join(query(a, b, L[p], l, m), query(a, b, R[p], m + 1, r)); 28 | } 29 | pst_t update(int a, pst_t x, int lp, int p, int l, int r){ 30 | if (l == r) 31 | return seg[p] = x; 32 | int m = (l + r) / 2; 33 | if (a <= m) 34 | return seg[p] = join(update(a, x, L[lp], L[p] = cnt++, l, m), seg[R[p] = R[lp]]); 35 | return seg[p] = join(seg[L[p] = L[lp]], update(a, x, R[lp], R[p] = cnt++, m + 1, r)); 36 | } 37 | //Public: 38 | //O(n) 39 | void build(int n2, int *v2){ 40 | n = n2, v = v2; 41 | T[0] = cnt++; 42 | build(0, 0, n - 1); 43 | } 44 | //O(log(n)) 45 | pst_t query(int a, int b, int tt){ 46 | return query(a, b, T[tt], 0, n - 1); 47 | } 48 | //O(log(n)) 49 | //update: v[idx] = x; 50 | int update(int idx, pst_t x, int tt = t){ 51 | update(idx, x, T[tt], T[++t] = cnt++, 0, n - 1); 52 | return t; 53 | } 54 | }; // namespace perseg 55 | --------------------------------------------------------------------------------