├── PDF ├── Almanaque.pdf └── Almanaque.tex ├── Codigos ├── Matemática │ ├── Inverso-Modular │ │ ├── modular_inverse.cpp │ │ ├── modular_inverse_coprime.cpp │ │ ├── modular_inverse_linear.cpp │ │ ├── modular_inverse_pow.cpp │ │ └── README.md │ ├── SMAWCK │ │ └── README.md │ ├── GCD │ │ ├── gcd.cpp │ │ ├── extended_gcd_recursive.cpp │ │ ├── extended_gcd.cpp │ │ └── README.md │ ├── NTT │ │ ├── Taylor-Shift │ │ │ ├── README.md │ │ │ └── taylor_shift.cpp │ │ ├── NTT-Big-Modulo │ │ │ └── README.md │ │ └── NTT │ │ │ ├── README.md │ │ │ └── ntt.cpp │ ├── Exponenciação-Modular-Rápida │ │ ├── README.md │ │ └── exp_mod.cpp │ ├── Fatoração-e-Primos │ │ ├── Teste-Primalidade │ │ │ ├── Teste-Primalidade-Naive │ │ │ │ ├── naive_is_prime.cpp │ │ │ │ └── README.md │ │ │ └── Miller-Rabin │ │ │ │ ├── README.md │ │ │ │ └── miller_rabin.cpp │ │ ├── Divisores │ │ │ ├── Divisores-Naive │ │ │ │ ├── README.md │ │ │ │ └── get_divs_naive.cpp │ │ │ └── Divisores-Rápido │ │ │ │ ├── README.md │ │ │ │ └── get_divs.cpp │ │ ├── Fatores │ │ │ ├── Fatoração-Naive │ │ │ │ ├── README.md │ │ │ │ └── naive_factorize.cpp │ │ │ └── Fatoração-Rápida │ │ │ │ ├── fast_factorize.cpp │ │ │ │ └── README.md │ │ ├── Crivo │ │ │ ├── Crivo │ │ │ │ ├── sieve.cpp │ │ │ │ └── README.md │ │ │ └── Crivo-Linear │ │ │ │ ├── README.md │ │ │ │ └── linear_sieve.cpp │ │ └── Pollard-Rho │ │ │ ├── README.md │ │ │ └── pollard_rho.cpp │ ├── Convolução │ │ ├── LCM-Convolution │ │ │ ├── README.md │ │ │ └── lcm_convolution.cpp │ │ ├── GCD-Convolution │ │ │ ├── README.md │ │ │ └── gcd_convolution.cpp │ │ ├── OR-Convolution │ │ │ ├── README.md │ │ │ └── or_convolution.cpp │ │ ├── XOR-Convolution │ │ │ ├── README.md │ │ │ └── xor_convolution.cpp │ │ ├── AND-Convolution │ │ │ ├── README.md │ │ │ └── and_convolution.cpp │ │ ├── Dirichlet-Convolution │ │ │ ├── Dirichlet-Convolution │ │ │ │ ├── README.md │ │ │ │ └── dirichlet_convolution.cpp │ │ │ ├── Dirichlet-Convolution-Prefix │ │ │ │ ├── dirichlet_convolution_prefix.cpp │ │ │ │ └── README.md │ │ │ └── Dirichlet-Inverse-Prefix │ │ │ │ ├── README.md │ │ │ │ └── dirichlet_inverse_prefix.cpp │ │ └── Subset-Convolution │ │ │ ├── README.md │ │ │ └── subset_convolution.cpp │ ├── Teorema-do-Resto-Chinês │ │ ├── README.md │ │ └── crt.cpp │ ├── Totiente-de-Euler │ │ ├── phi.cpp │ │ ├── phi_1_to_n.cpp │ │ └── README.md │ ├── Floor-Values │ │ ├── floor_values.cpp │ │ └── README.md │ ├── Floor-and-Mod-Sum-of-Arithmetic-Progressions │ │ ├── README.md │ │ └── floor_and_mod_sum_of_arithmetic_progressions.cpp │ ├── Discrete-Root │ │ └── README.md │ ├── Polinomios │ │ └── README.md │ ├── FFT │ │ └── README.md │ ├── Continued-Fractions │ │ └── README.md │ ├── Eliminação-Gaussiana │ │ ├── Gauss │ │ │ ├── README.md │ │ │ └── gauss.cpp │ │ └── Gauss-Mod-2 │ │ │ ├── gauss_mod2.cpp │ │ │ └── README.md │ └── XOR-Gauss │ │ ├── xor_gauss.cpp │ │ └── README.md ├── Extra │ ├── CPP │ │ ├── README.md │ │ └── template.cpp │ ├── Vim │ │ ├── README.md │ │ └── vimrc │ ├── Run │ │ ├── run │ │ └── README.md │ ├── Random │ │ ├── rand.cpp │ │ └── README.md │ ├── Stress-Test │ │ ├── README.md │ │ └── stress.sh │ ├── Debug │ │ ├── README.md │ │ └── debug.cpp │ └── Unordered-Custom-Hash │ │ ├── README.md │ │ └── custom_hash.cpp ├── Paradigmas │ ├── All-Submasks │ │ ├── all_submask.cpp │ │ └── README.md │ ├── DP-de-Permutacao │ │ ├── README.md │ │ └── tsp_dp.cpp │ ├── Mo │ │ ├── Mo-Update │ │ │ └── README.md │ │ └── Mo │ │ │ ├── README.md │ │ │ └── mo.cpp │ ├── Busca-Binaria-Paralela │ │ └── README.md │ ├── Busca-Ternaria │ │ ├── busca_ternaria.cpp │ │ ├── busca_ternaria_discreta.cpp │ │ └── README.md │ ├── Convex-Hull-Trick │ │ ├── README.md │ │ └── Convex Hull Trick.cpp │ ├── Divide-and-Conquer │ │ ├── README.md │ │ └── dc.cpp │ └── Exponenciação-de-Matriz │ │ ├── matrix_exp.cpp │ │ └── README.md ├── Estruturas-de-Dados │ ├── Disjoint-Set-Union │ │ ├── DSU-Rollback-Bipartido │ │ │ ├── README.md │ │ │ └── bipartite_rollback_dsu.cpp │ │ ├── DSU │ │ │ ├── README.md │ │ │ └── dsu.cpp │ │ ├── Offline-DSU │ │ │ └── README.md │ │ ├── DSU-Bipartido │ │ │ ├── README.md │ │ │ └── bipartite_dsu.cpp │ │ └── DSU-Rollback │ │ │ ├── README.md │ │ │ └── rollback_dsu.cpp │ ├── Segment-Tree │ │ ├── Segment-Tree-2D │ │ │ ├── README.md │ │ │ └── seg_tree_2d.cpp │ │ ├── Segment-Tree-PA │ │ │ └── README.md │ │ ├── Segment-Tree-Iterativa │ │ │ ├── README.md │ │ │ └── itseg_tree.cpp │ │ ├── Segment-Tree-Beats │ │ │ └── README.md │ │ ├── Segment-Tree-Lazy-Esparsa │ │ │ └── README.md │ │ ├── Segment-Tree │ │ │ └── README.md │ │ ├── Segment-Tree-Persistente │ │ │ └── README.md │ │ ├── Segment-Tree-Lazy │ │ │ └── README.md │ │ ├── Segment-Tree-Esparsa │ │ │ ├── README.md │ │ │ └── seg_tree_sparse.cpp │ │ └── Segment-Tree-Kadane │ │ │ └── README.md │ ├── Sparse-Table │ │ ├── Disjoint-Sparse-Table │ │ │ ├── README.md │ │ │ └── dst.cpp │ │ └── Sparse-Table │ │ │ ├── README.md │ │ │ └── sparse_table.cpp │ ├── Merge-Sort-Tree │ │ ├── Merge-Sort-Tree-Update │ │ │ └── README.md │ │ └── Merge-Sort-Tree │ │ │ └── README.md │ ├── Fenwick-Tree │ │ ├── Kd-Fenwick-Tree │ │ │ ├── README.md │ │ │ └── kd_fenwick_tree.cpp │ │ └── Fenwick │ │ │ ├── README.md │ │ │ └── fenwick_tree.cpp │ ├── Ordered-Set │ │ └── ordered_set.cpp │ ├── Operation-Queue │ │ ├── README.md │ │ └── op_queue.cpp │ ├── Operation-Deque │ │ ├── README.md │ │ └── op_deque.cpp │ ├── Treap │ │ └── README.md │ ├── Operation-Stack │ │ ├── op_stack.cpp │ │ └── README.md │ ├── XOR-Trie │ │ ├── README.md │ │ └── xor_trie.cpp │ ├── Interval-Tree │ │ ├── README.md │ │ └── interval_tree.cpp │ ├── Implicit-Treap │ │ └── README.md │ └── LiChao-Tree │ │ ├── README.md │ │ └── lichao_tree.cpp ├── Grafos │ ├── Pontes │ │ ├── Pontes │ │ │ ├── README.md │ │ │ └── find_bridges.cpp │ │ └── Componentes-Aresta-Biconexas │ │ │ ├── README.md │ │ │ └── ebcc_components.cpp │ ├── Binary-Lifting │ │ ├── Binary-Lifting-Query-Aresta │ │ │ └── README.md │ │ ├── Binary-Lifting-Query-2 │ │ │ └── README.md │ │ ├── Binary-Lifting-LCA │ │ │ ├── README.md │ │ │ └── binary_lifting_lca.cpp │ │ └── Binary-Lifting-Query │ │ │ └── README.md │ ├── LCA │ │ ├── README.md │ │ └── lca.cpp │ ├── Shortest-Paths │ │ ├── Bellman-Ford │ │ │ ├── README.md │ │ │ └── bellman_ford.cpp │ │ ├── SPFA │ │ │ ├── README.md │ │ │ └── spfa.cpp │ │ ├── BFS │ │ │ ├── README.md │ │ │ └── bfs.cpp │ │ ├── 01-BFS │ │ │ ├── README.md │ │ │ └── bfs01.cpp │ │ ├── Floyd-Warshall │ │ │ ├── README.md │ │ │ └── floyd_warshall.cpp │ │ ├── Dijkstra │ │ │ ├── README.md │ │ │ └── dijkstra.cpp │ │ └── Dial │ │ │ ├── README.md │ │ │ └── dial.cpp │ ├── Ciclos │ │ ├── Find-Negative-Cycle │ │ │ ├── README.md │ │ │ └── find_negative_cycle.cpp │ │ └── Find-Cycle │ │ │ ├── README.md │ │ │ └── find_cycle.cpp │ ├── Pontos-de-Articulacao │ │ ├── README.md │ │ └── articulation_points.cpp │ ├── Virtual-Tree │ │ ├── README.md │ │ └── virtual_tree.cpp │ ├── Inverse-Graph │ │ ├── README.md │ │ └── inverse_graph.cpp │ ├── Block-Cut-Tree │ │ └── README.md │ ├── Kosaraju │ │ ├── README.md │ │ └── kosaraju.cpp │ ├── Matching │ │ └── Hungaro │ │ │ ├── README.md │ │ │ └── hungarian.cpp │ ├── Kruskal │ │ ├── kruskal.cpp │ │ └── README.md │ ├── Centroids │ │ ├── Centroid │ │ │ ├── README.md │ │ │ └── find_centroid.cpp │ │ └── Centroid-Decomposition │ │ │ ├── README.md │ │ │ └── centroid_decomposition.cpp │ ├── Stoer–Wagner-Min-Cut │ │ ├── README.md │ │ └── stoer_wagner.cpp │ ├── Centro-e-Diametro │ │ ├── README.md │ │ └── graph_center.cpp │ ├── Caminho-Euleriano │ │ ├── Caminho-Euleriano-Nao-Direcionado │ │ │ └── README.md │ │ └── Caminho-Euleriano-Direcionado │ │ │ └── README.md │ ├── Fluxo │ │ └── README.md │ ├── 2-SAT │ │ └── README.md │ └── HLD │ │ ├── HLD-Vértice │ │ └── README.md │ │ └── HLD-Aresta │ │ └── README.md ├── Primitivas │ ├── Ponto-2D │ │ ├── README.md │ │ └── point2d.cpp │ └── Modular-Int │ │ ├── README.md │ │ └── mint.cpp ├── String │ ├── Trie │ │ ├── README.md │ │ └── trie.cpp │ ├── Patricia-Tree │ │ ├── patricia_tree.cpp │ │ └── README.md │ ├── Z-function │ │ ├── README.md │ │ └── z.cpp │ ├── Manacher │ │ ├── README.md │ │ └── manacher.cpp │ ├── Lyndon │ │ ├── min_cyclic_shift.cpp │ │ ├── README.md │ │ └── duval.cpp │ ├── Prefix-Function-KMP │ │ ├── KMP │ │ │ ├── README.md │ │ │ └── kmp.cpp │ │ └── Automato-KMP │ │ │ ├── README.md │ │ │ └── aut_kmp.cpp │ ├── Suffix-Array │ │ ├── README.md │ │ ├── suffix_array_busca.cpp │ │ └── suffix_array.cpp │ ├── EertreE │ │ └── README.md │ ├── Hashing │ │ ├── Hashing-Dinâmico │ │ │ ├── README.md │ │ │ └── dynamic_hashing.cpp │ │ └── Hashing │ │ │ ├── README.md │ │ │ └── hashing.cpp │ ├── Aho-Corasick │ │ ├── README.md │ │ └── aho_corasick.cpp │ └── Suffix-Automaton │ │ └── README.md └── Geometria │ └── Convex-Hull │ ├── README.md │ └── convex_hull.cpp ├── .gitignore ├── LaTeX ├── chapters │ ├── 01-cpp │ │ ├── index.tex │ │ ├── compilador.tex │ │ ├── constantes.tex │ │ └── pragmas.tex │ └── 02-teorico │ │ ├── index.tex │ │ ├── problema-da-realizacao-de-grafos.tex │ │ ├── teoria-dos-numeros.tex │ │ ├── definicoes.tex │ │ ├── sequencias-numericas.tex │ │ └── analise-combinatoria.tex ├── configs │ ├── titlesec.tex │ └── packages.tex ├── main.tex └── preamble.tex ├── containers └── latex.Dockerfile ├── .clang-format └── .github └── workflows ├── clang-format-check.yml └── generate_almanaque_pdf.yml /PDF/Almanaque.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BRUTEUdesc/AlmanaqueBrute/HEAD/PDF/Almanaque.pdf -------------------------------------------------------------------------------- /Codigos/Matemática/Inverso-Modular/modular_inverse.cpp: -------------------------------------------------------------------------------- 1 | ll inv(ll a) { return exp_mod(a, MOD - 2); } 2 | -------------------------------------------------------------------------------- /Codigos/Matemática/SMAWCK/README.md: -------------------------------------------------------------------------------- 1 | # SMAWCK 2 | 3 | (max, +) convolution 4 | Créditos: tfg 5 | 6 | -------------------------------------------------------------------------------- /Codigos/Extra/CPP/README.md: -------------------------------------------------------------------------------- 1 | # [Template C++](template.cpp) 2 | 3 | Template de C++ para usar na Maratona. -------------------------------------------------------------------------------- /Codigos/Extra/Vim/README.md: -------------------------------------------------------------------------------- 1 | # [Vimrc](vimrc) 2 | 3 | Template de arquivo `.vimrc` para configuração do Vim. 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/GCD/gcd.cpp: -------------------------------------------------------------------------------- 1 | long long gcd(long long a, long long b) { return (b == 0) ? a : gcd(b, a % b); } 2 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/All-Submasks/all_submask.cpp: -------------------------------------------------------------------------------- 1 | int mask; 2 | for (int sub = mask; sub; sub = (sub - 1) & mask) { } 3 | -------------------------------------------------------------------------------- /Codigos/Extra/Run/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | g++ -std=c++20 -DBRUTE -O2 -Wall -Wextra -Wconversion -Wfatal-errors -fsanitize=address,undefined $1 && ./a.out -------------------------------------------------------------------------------- /Codigos/Paradigmas/All-Submasks/README.md: -------------------------------------------------------------------------------- 1 | # [All Submask](all_submasks.cpp) 2 | 3 | Percorre todas as submáscaras de uma máscara em $\mathcal{O}(3^n)$. 4 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU-Rollback-Bipartido/README.md: -------------------------------------------------------------------------------- 1 | # [DSU Rollback Bipartido](bipartite_rollback_dsu.cpp) 2 | 3 | DSU com rollback e bipartido. 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | in 2 | out 3 | out.* 4 | *.out 5 | venv 6 | Almanaque.html 7 | .idea 8 | .vscode 9 | .DS_Store 10 | *~ 11 | *.swp 12 | *.swo 13 | tmp/ 14 | LaTeX/generated/ 15 | -------------------------------------------------------------------------------- /Codigos/Matemática/NTT/Taylor-Shift/README.md: -------------------------------------------------------------------------------- 1 | # [Taylor Shift](taylor_shift.cpp) 2 | 3 | Usa NTT para computar o polinômio $p(x + k)$, dados $p$ e $k$. A complexidade é $O(n \log n)$. -------------------------------------------------------------------------------- /Codigos/Matemática/Exponenciação-Modular-Rápida/README.md: -------------------------------------------------------------------------------- 1 | # [Exponenciação modular rápida](exp_mod.cpp) 2 | 3 | Computa $(\text{base} ^ \text{exp}) \mod MOD$ em $\mathcal{O}(\log(\text{exp}))$. -------------------------------------------------------------------------------- /Codigos/Extra/Random/rand.cpp: -------------------------------------------------------------------------------- 1 | mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()); 2 | 3 | int uniform(int l, int r) { return uniform_int_distribution(l, r)(rng); } 4 | -------------------------------------------------------------------------------- /LaTeX/chapters/01-cpp/index.tex: -------------------------------------------------------------------------------- 1 | \section{C++} 2 | 3 | \input{chapters/01-cpp/compilador} 4 | \input{chapters/01-cpp/stl} 5 | \input{chapters/01-cpp/pragmas} 6 | \input{chapters/01-cpp/constantes} 7 | -------------------------------------------------------------------------------- /Codigos/Matemática/Inverso-Modular/modular_inverse_coprime.cpp: -------------------------------------------------------------------------------- 1 | int inv(int a) { 2 | int x, y; 3 | int g = extended_gcd(a, MOD, x, y); 4 | if (g == 1) return (x % m + m) % m; 5 | return -1; 6 | } 7 | -------------------------------------------------------------------------------- /LaTeX/configs/titlesec.tex: -------------------------------------------------------------------------------- 1 | \usepackage[compact]{titlesec} 2 | 3 | \titlespacing*{\section}{0pt}{*0.6}{*0.3} 4 | \titlespacing*{\subsection}{0pt}{*0.5}{*0.25} 5 | \titlespacing*{\subsubsection}{0pt}{*0.4}{*0.2} 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Inverso-Modular/modular_inverse_linear.cpp: -------------------------------------------------------------------------------- 1 | ll inv[MAX]; 2 | 3 | void compute_inv(const ll m = MOD) { 4 | inv[1] = 1; 5 | for (int i = 2; i < MAX; i++) inv[i] = m - (m / i) * inv[m % i] % m; 6 | } 7 | -------------------------------------------------------------------------------- /Codigos/Grafos/Pontes/Pontes/README.md: -------------------------------------------------------------------------------- 1 | # [Pontes](find_bridges.cpp) 2 | 3 | Algoritmo que acha pontes em um grafo utilizando DFS. $\mathcal{O}(V + E)$. Pontes são arestas cuja remoção aumenta o número de componentes conexas do grafo. -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Teste-Primalidade/Teste-Primalidade-Naive/naive_is_prime.cpp: -------------------------------------------------------------------------------- 1 | bool is_prime(int n) { 2 | for (int d = 2; d * d <= n; d++) 3 | if (n % d == 0) return false; 4 | return true; 5 | } 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/LCM-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [LCM Convolution](lcm_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ $C[i] = \sum_{\substack{lcm(j, k) = i}} A[j] \cdot B[k]$ em $\mathcal{O}(N \cdot \log N)$. 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Teorema-do-Resto-Chinês/README.md: -------------------------------------------------------------------------------- 1 | # [Teorema do Resto Chinês](crt.cpp) 2 | 3 | Algoritmo que resolve o sistema $x \equiv a_i \pmod{m_i}$, onde $m_i$ são primos entre si. 4 | 5 | Retorna $-1$ se a resposta não existir. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/GCD-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [GCD Convolution](gcd_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ onde $C[i] = \sum_{\substack{gcd(j, k) = i}} A[j] \cdot B[k]$ em $\mathcal{O}(N \cdot \log N)$. 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/OR-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [OR Convolution](or_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ tal que $C[i] = \sum_{\substack{(j \| k) = i}} A[j] \cdot B[k]$ em $\mathcal{O}(N \cdot \log N)$ 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/XOR-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [XOR Convolution](xor_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ tal que $C[i] = \sum_{\substack{(j \oplus k) = i}} A[j] \cdot B[k]$ em $\mathcal{O}(N \cdot \log N)$ 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Divisores/Divisores-Naive/README.md: -------------------------------------------------------------------------------- 1 | # [Divisores Naive](get_divs_naive.cpp) 2 | 3 | Algoritmo que obtém todos os divisores de um número $X$ em $\mathcal{O}(\sqrt{X})$. Muito similar ao algoritmo naive de fatoração. -------------------------------------------------------------------------------- /Codigos/Extra/CPP/template.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #define endl '\n' 3 | using namespace std; 4 | using ll = long long; 5 | 6 | void solve() { } 7 | 8 | signed main() { 9 | cin.tie(0)->sync_with_stdio(0); 10 | solve(); 11 | } 12 | -------------------------------------------------------------------------------- /Codigos/Grafos/Binary-Lifting/Binary-Lifting-Query-Aresta/README.md: -------------------------------------------------------------------------------- 1 | # [Binary Lifting Query Aresta](binary_lifting_query_aresta.cpp) 2 | 3 | O mesmo Binary Lifting de query em nodos, porém agora com os valores nas arestas. As complexidades são as mesmas. 4 | -------------------------------------------------------------------------------- /Codigos/Grafos/LCA/README.md: -------------------------------------------------------------------------------- 1 | # [LCA](lca.cpp) 2 | 3 | Algoritmo para computar Lowest Common Ancestor usando Euler Tour e Sparse Table (descrita na seção Estruturas de Dados), com pré-processamento em $\mathcal{O}(N \log N)$ e consulta em $\mathcal{O}(1)$. 4 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Bellman-Ford/README.md: -------------------------------------------------------------------------------- 1 | # [Bellman-Ford](bellman_ford.cpp) 2 | 3 | Encontra o caminho mais curto entre um nodo e todos os outros nodos de um grafo em $\mathcal{O}(|V| * |E|)$. 4 | 5 | **Importante**: Detecta ciclos negativos. 6 | -------------------------------------------------------------------------------- /Codigos/Grafos/Ciclos/Find-Negative-Cycle/README.md: -------------------------------------------------------------------------------- 1 | # [Find Negative Cycle](find_negative_cycle.cpp) 2 | 3 | Encontra um ciclo com soma negativa no grafo em $\mathcal{O}(|V| * |E|)$ usando o algoritmo Bellman Ford, retorna um vetor vazio caso nenhum ciclo seja encontrado. 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Fatores/Fatoração-Naive/README.md: -------------------------------------------------------------------------------- 1 | # [Fatoração Naive](naive_factorize.cpp) 2 | 3 | Fatoração de um número. A função `factorize(X)` retorna os fatores primos de $X$ em ordem crescente. A complexidade do algoritmo é $\mathcal{O}(\sqrt{X})$. -------------------------------------------------------------------------------- /Codigos/Grafos/Pontos-de-Articulacao/README.md: -------------------------------------------------------------------------------- 1 | # [Pontos de articulação](articulation_points.cpp) 2 | 3 | Algoritmo que acha pontos de articulação em um grafo utilizando DFS. $\mathcal{O}(V + E)$. Pontos de articulação são nodos cuja remoção aumenta o número de componentes conexas do grafo. -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/SPFA/README.md: -------------------------------------------------------------------------------- 1 | # [Shortest Path Fast Algorithm](spfa.cpp) 2 | 3 | Encontra o caminho mais curto entre um nodo e todos os outros nodos de um grafo em $\mathcal{O}(|V| * |E|)$. Na prática, é bem mais rápido que o Bellman-Ford. 4 | 5 | Detecta ciclos negativos. -------------------------------------------------------------------------------- /Codigos/Matemática/Exponenciação-Modular-Rápida/exp_mod.cpp: -------------------------------------------------------------------------------- 1 | ll exp_mod(ll base, ll exp) { 2 | ll b = base, res = 1; 3 | while (exp) { 4 | if (exp & 1) res = (res * b) % MOD; 5 | b = (b * b) % MOD; 6 | exp /= 2; 7 | } 8 | return res; 9 | } 10 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/DP-de-Permutacao/README.md: -------------------------------------------------------------------------------- 1 | # [DP de Permutação](tsp_dp.cpp) 2 | 3 | Otimização do problema do Caixeiro Viajante 4 | 5 | * Complexidade de tempo: $\mathcal{O}(n^2 * 2^n)$ 6 | 7 | Para rodar a função basta setar a matriz de adjacência `dist` e chamar `solve(0,0,n)`. 8 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/AND-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [AND Convolution](and_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ onde $C[i] = \sum_{\substack{(j \land k) = i}} A[j] \cdot B[k]$ em $\mathcal{O}(N \cdot \log N)$. 4 | 5 | Obs: $\land$ representa o bitwise and. 6 | -------------------------------------------------------------------------------- /Codigos/Extra/Stress-Test/README.md: -------------------------------------------------------------------------------- 1 | # [Stress Test](stress.sh) 2 | 3 | Script muito útil para achar casos em que sua solução gera uma resposta incorreta. 4 | Deve-se criar uma solução bruteforce (que garantidamente está correta, ainda que seja lenta) e um gerador de casos aleatórios para seu problema. -------------------------------------------------------------------------------- /Codigos/Grafos/Ciclos/Find-Cycle/README.md: -------------------------------------------------------------------------------- 1 | # [Find Cycle](find_cycle.cpp) 2 | 3 | Encontra um ciclo no grafo em $\mathcal{O}(|V| + |E|)$, retorna um vetor vazio caso nenhum ciclo seja encontrado. O método `build` possui uma flag que indica se o algoritmo deve aceitar ciclos de tamanho 1 ou ciclos de tamanho 2. -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Dirichlet-Convolution/Dirichlet-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [Dirichlet Convolution](dirichlet_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ onde $C[n] = \sum_{d \mid n} A[d] \cdot B\Big[\frac{n}{d}\Big]$, ou seja, a convolução de Dirichlet, em $\mathcal{O}(N)$. 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Teste-Primalidade/Teste-Primalidade-Naive/README.md: -------------------------------------------------------------------------------- 1 | # [Teste Primalidade Naive](naive_is_prime.cpp) 2 | 3 | Teste de primalidade "ingênuo". A função `is_prime(X)` retorna verdadeiro se $X$ é primo e falso caso contrário. A complexidade do algoritmo é $\mathcal{O}(\sqrt{X})$. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-2D/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree 2D](seg_tree.cpp) 2 | 3 | Segment Tree em 2 dimensões, suporta operações de update pontual e consulta em intervalo. A construção é $\mathcal{O}(n \cdot m)$ e as operações de consulta e update são $\mathcal{O}(\log n \cdot \log m)$. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Sparse-Table/Disjoint-Sparse-Table/README.md: -------------------------------------------------------------------------------- 1 | # [Disjoint Sparse Table](dst.cpp) 2 | 3 | Uma Sparse Table melhorada, construção ainda em $\mathcal{O}(n \log n)$, mas agora suporta queries de **qualquer** operação associativa em $\mathcal{O}(1)$, não precisando mais ser idempotente. 4 | -------------------------------------------------------------------------------- /Codigos/Extra/Vim/vimrc: -------------------------------------------------------------------------------- 1 | set nu ai si cindent et ts=4 sw=4 so=10 nosm undofile 2 | 3 | inoremap {} {} 4 | " remap de chaves 5 | 6 | au BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal! g'\"" | endif 7 | " volta pro lugar onde estava quando saiu do arquivo 8 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/BFS/README.md: -------------------------------------------------------------------------------- 1 | # [BFS](bfs.cpp) 2 | 3 | Computa o menor caminho entre nodos de um grafo com arestas de peso 1. 4 | 5 | Dado um nodo $s$, computa o menor caminho de $s$ para todos os outros nodos em $\mathcal{O}(V + E)$. 6 | 7 | **Importante**: Todas arestas do grafo devem ter peso 1. -------------------------------------------------------------------------------- /Codigos/Extra/Run/README.md: -------------------------------------------------------------------------------- 1 | # [Run](run) 2 | 3 | Arquivo útil para compilar e rodar um programa em `C++` com flags que ajudam a debugar. 4 | Basta criar um arquivo chamado `run`, adicionar o código abaixo e dar permissão de execução com `chmod +x run`. 5 | Para executar um arquivo `a.cpp`, basta rodar `./run a.cpp`. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/GCD/extended_gcd_recursive.cpp: -------------------------------------------------------------------------------- 1 | ll extended_gcd(ll a, ll b, ll &x, ll &y) { 2 | if (b == 0) { 3 | x = 1; 4 | y = 0; 5 | return a; 6 | } else { 7 | ll g = extended_gcd(b, a % b, y, x); 8 | y -= a / b * x; 9 | return g; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Codigos/Primitivas/Ponto-2D/README.md: -------------------------------------------------------------------------------- 1 | # [Ponto 2D](point2d.cpp) 2 | 3 | Estrutura que representa um ponto no plano cartesiano em duas dimensões. Suporta operações de soma, subtração, multiplicação por escalar, produto escalar, produto vetorial e distância euclidiana. Pode ser usado também para representar um vetor. 4 | -------------------------------------------------------------------------------- /Codigos/Grafos/Virtual-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [Virtual Tree](virtual_tree.cpp) 2 | 3 | Dado um conjunto de nodos $S$, cria uma árvore com todos os nodos do conjunto e os `LCA` de todos os pares de nodos 4 | desse conjunto em $\mathcal{O}(|S| \cdot \log |S|)$. 5 | 6 | **Obs**: Precisa do código de LCA encontrado em `Grafos/Binary-Lifting-LCA`. 7 | -------------------------------------------------------------------------------- /Codigos/String/Trie/README.md: -------------------------------------------------------------------------------- 1 | # [Trie](trie.cpp) 2 | 3 | Estrutura que guarda informações indexadas por palavra. 4 | 5 | Útil encontrar todos os prefixos inseridos anteriormente de uma palavra específica. 6 | 7 | * Complexidade de tempo (Update): $\mathcal{O}(|S|)$ 8 | * Complexidade de tempo (Consulta de palavra): $\mathcal{O}(|S|)$ 9 | -------------------------------------------------------------------------------- /Codigos/Grafos/Inverse-Graph/README.md: -------------------------------------------------------------------------------- 1 | # [Inverse Graph](inverse_graph.cpp) 2 | 3 | Algoritmo que encontra as componentes conexas quando se é dado o grafo complemento. 4 | 5 | Resolve problemas em que se deseja encontrar as componentes conexas quando são dadas as arestas que não pertencem ao grafo, em $\mathcal{O}(N \cdot \log N + N \cdot \log M)$. -------------------------------------------------------------------------------- /Codigos/Matemática/Totiente-de-Euler/phi.cpp: -------------------------------------------------------------------------------- 1 | int phi(int n) { 2 | int result = n; 3 | for (int i = 2; i * i <= n; i++) { 4 | if (n % i == 0) { 5 | while (n % i == 0) n /= i; 6 | result -= result / i; 7 | } 8 | } 9 | if (n > 1) result -= result / n; 10 | return result; 11 | } 12 | -------------------------------------------------------------------------------- /Codigos/Matemática/Totiente-de-Euler/phi_1_to_n.cpp: -------------------------------------------------------------------------------- 1 | vector phi_1_to_n(int n) { 2 | vector phi(n + 1); 3 | for (int i = 0; i <= n; i++) phi[i] = i; 4 | for (int i = 2; i <= n; i++) { 5 | if (phi[i] == i) 6 | for (int j = i; j <= n; j += i) phi[j] -= phi[j] / i; 7 | } 8 | return phi; 9 | } 10 | -------------------------------------------------------------------------------- /Codigos/String/Patricia-Tree/patricia_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace __gnu_pbds; 5 | typedef trie< 6 | string, 7 | null_type, 8 | trie_string_access_traits<>, 9 | pat_trie_tag, 10 | trie_prefix_search_node_update> 11 | patricia_tree; 12 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Merge-Sort-Tree/Merge-Sort-Tree-Update/README.md: -------------------------------------------------------------------------------- 1 | # [Merge Sort Tree com Update](mergesort_tree_update.cpp) 2 | 3 | Merge Sort Tree com updates pontuais. O update é $\mathcal{O}(\log^2 N)$ e a query é $\mathcal{O}(\log^2 N)$, ambos com constante alta. 4 | 5 | **Obs**: usa a estrutura `ordered_set`, descrita nesse Almanaque também. -------------------------------------------------------------------------------- /Codigos/Paradigmas/Mo/Mo-Update/README.md: -------------------------------------------------------------------------------- 1 | # [Mo com Update](mo_update.cpp) 2 | 3 | Resolve queries complicadas Offline de forma rápida. 4 | 5 | Permite que existam **UPDATES PONTUAIS!** 6 | É preciso manter uma estrutura que adicione e remova elementos nas extremidades de um range (tipo janela). A complexidade é $\mathcal{O}(Q \cdot \sqrt[3]{N^2})$ 7 | -------------------------------------------------------------------------------- /Codigos/Extra/Debug/README.md: -------------------------------------------------------------------------------- 1 | # [Debug](debug.cpp) 2 | 3 | Template para debugar variáveis em `C++`. Até a linha 17 é opcional: serve para permitir o debug de `std::pair` e `std::vector`. 4 | 5 | Para usar, basta compilar com a flag `-DBRUTE` (o template `run` já possui essa flag). No código, utilize `debug(x, y, z)` para debugar as variáveis `x`, `y` e `z`. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Subset-Convolution/README.md: -------------------------------------------------------------------------------- 1 | # [Subset Convolution](subset_convolution.cpp) 2 | 3 | Calcula o vetor $C$ a partir de $A$ e $B$ tal que $C[i] = \sum_{\substack{(j \| k) = i}, \substack{(j \land k) = 0}} A[j] \cdot B[k]$ em $\mathcal{O}(N \cdot \log^2 N)$ 4 | 5 | Obs: $\land$ representa o bitwise and e $\|$ representa o bitwise or. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Inverso-Modular/modular_inverse_pow.cpp: -------------------------------------------------------------------------------- 1 | const ll INVB = (MOD + 1) / 2; // Modular inverse of the base, 2 | // for 2 it is (MOD+1)/2 3 | 4 | ll inv[MAX]; // Modular inverse of b^i 5 | 6 | void compute_inv() { 7 | inv[0] = 1; 8 | for (int i = 1; i < MAX; i++) inv[i] = inv[i - 1] * INVB % MOD; 9 | } 10 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Fatores/Fatoração-Naive/naive_factorize.cpp: -------------------------------------------------------------------------------- 1 | vector factorize(int n) { 2 | vector factors; 3 | for (int d = 2; d * d <= n; d++) { 4 | while (n % d == 0) { 5 | factors.push_back(d); 6 | n /= d; 7 | } 8 | } 9 | if (n != 1) factors.push_back(n); 10 | return factors; 11 | } 12 | -------------------------------------------------------------------------------- /Codigos/Matemática/GCD/extended_gcd.cpp: -------------------------------------------------------------------------------- 1 | int extended_gcd(int a, int b, int &x, int &y) { 2 | x = 1, y = 0; 3 | int x1 = 0, y1 = 1; 4 | while (b) { 5 | int q = a / b; 6 | tie(x, x1) = make_tuple(x1, x - q * x1); 7 | tie(y, y1) = make_tuple(y1, y - q * y1); 8 | tie(a, b) = make_tuple(b, a - q * b); 9 | } 10 | return a; 11 | } 12 | -------------------------------------------------------------------------------- /Codigos/String/Z-function/README.md: -------------------------------------------------------------------------------- 1 | # [Z Function](z.cpp) 2 | 3 | O algoritmo abaixo computa o vetor Z de uma string, definido por: 4 | 5 | $$ z[i] = \max\{k \mid s[0,k) = s[i,i+k)\} $$ 6 | 7 | Em outras palavras, $z[i]$ é o tamanho do maior prefixo de $s$ é prefixo de $s[i,|s|-1]$. 8 | 9 | É muito semelhante ao KMP em termos de aplicações. Usado principalmente para pattern matching. -------------------------------------------------------------------------------- /Codigos/Paradigmas/Busca-Binaria-Paralela/README.md: -------------------------------------------------------------------------------- 1 | # [Busca Binária Paralela](busca_binaria_paralela.cpp) 2 | 3 | Faz a busca binária para múltiplas consultas quando a busca binária é muito pesada. A complexidade é $\mathcal{O}((N+Q) \log(N) \cdot \mathcal{O}(F))$, onde $N$ é o tamanho do espaço de busca, $Q$ é o número de consultas, e $\mathcal{O}(F)$ é o custo de avaliação da função. 4 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Crivo/Crivo/sieve.cpp: -------------------------------------------------------------------------------- 1 | namespace Sieve { 2 | const int P = 5e6 + 1; 3 | vector is_prime(P, true); 4 | void build() { 5 | is_prime[0] = is_prime[1] = 0; 6 | for (int i = 2; i < P; i++) { 7 | if (is_prime[i]) 8 | for (int j = i + i; j < P; j += i) is_prime[j] = 0; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Divisores/Divisores-Naive/get_divs_naive.cpp: -------------------------------------------------------------------------------- 1 | vector get_divs(int n) { 2 | vector divs; 3 | for (int d = 1; d * d <= n; d++) { 4 | if (n % d == 0) { 5 | divs.push_back(d); 6 | if (d * d != n) divs.push_back(n / d); 7 | } 8 | } 9 | sort(divs.begin(), divs.end()); 10 | return divs; 11 | } 12 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Fenwick-Tree/Kd-Fenwick-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [KD Fenwick Tree](kd_fenwick_tree.cpp) 2 | 3 | Fenwick Tree em $k$ dimensões. Faz apenas queries de prefixo e updates pontuais em $\mathcal{O}(k \cdot \log^k n)$. Para queries em range, deve-se fazer inclusão-exclusão, porém a complexidade fica exponencial, para $k$ dimensões a query em range é $\mathcal{O}(2^k \cdot k \cdot \log^k n)$. 4 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-PA/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree](seg_tree.cpp) 2 | 3 | Implementação de Segment Tree para soma de Progressão Aritimética, suporta operações de consulta em intervalo e update em range. Está implementada para soma, mas pode ser modificada para outras operações. A construção é $\mathcal{O}(n)$ e as operações de consulta e update são $\mathcal{O}(\log n)$. 4 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/01-BFS/README.md: -------------------------------------------------------------------------------- 1 | # [01 BFS](bfs01.cpp) 2 | 3 | Computa o menor caminho entre nodos de um grafo com arestas de peso 0 ou 1. 4 | 5 | Dado um nodo $s$, computa o menor caminho de $s$ para todos os outros nodos em $\mathcal{O}(V + E)$. 6 | 7 | Muito semelhante a uma BFS, mas usa uma `deque` (fila dupla) ao invés de uma fila comum. 8 | 9 | **Importante**: As arestas só podem ter peso 0 ou 1. -------------------------------------------------------------------------------- /Codigos/Matemática/Floor-Values/floor_values.cpp: -------------------------------------------------------------------------------- 1 | void floor_values(ll n) { 2 | ll j = 1; 3 | while (j <= n) { 4 | ll floor_now = n / j; 5 | ll last_j = n / floor_now; 6 | // j -> primeiro inteiro que tem floor_now como floor 7 | // last_j -> ultimo inteiro que tem floor_now como floor 8 | 9 | // faz algo 10 | 11 | j = last_j + 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Codigos/Matemática/Totiente-de-Euler/README.md: -------------------------------------------------------------------------------- 1 | # Totiente de Euler 2 | 3 | Código para computar a função Totiente de Euler, que conta quantos números inteiros positivos menores que $N$ são coprimos com $N$. A função é denotada por $\phi(N)$. 4 | 5 | É possível computar o totiente de Euler para um único número em $\mathcal{O}(\sqrt{N})$ e para todos os números entre $1$ e $N$ em $\mathcal{O}(N \cdot \log (\log N))$. 6 | -------------------------------------------------------------------------------- /Codigos/Geometria/Convex-Hull/README.md: -------------------------------------------------------------------------------- 1 | # [Convex Hull](convex_hull.cpp) 2 | 3 | Algoritmo Graham's Scan para encontrar o fecho convexo de um conjunto de pontos em $\mathcal{O}(n \log n)$. Retorna os pontos do fecho convexo em sentido horário. 4 | 5 | **Definição**: o fecho convexo de um conjunto de pontos é o menor polígono convexo que contém todos os pontos do conjunto. 6 | 7 | **Obs**: utiliza a primitiva `Ponto 2D`. 8 | -------------------------------------------------------------------------------- /Codigos/Grafos/Block-Cut-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [Block Cut Tree](block_cut_tree.cpp) 2 | 3 | Algoritmo que separa o grafo em componentes biconexas em $\mathcal{O}(V + E)$. 4 | 5 | - `id[u]` é o index do nodo `u` na Block Cut Tree. 6 | - `is_articulation_point(u)` diz se o nodo `u` é ou não é um ponto de articulação. 7 | - `number_of_splits(u)` diz a quantidade de componentes conexas que o grafo 8 | terá se o nodo `u` for removido. 9 | -------------------------------------------------------------------------------- /Codigos/Grafos/Kosaraju/README.md: -------------------------------------------------------------------------------- 1 | # [Kosaraju](kosaraju.cpp) 2 | 3 | Algoritmo que encontra as componentes fortemente conexas (SCCs) de um grafo direcionado. 4 | O algoritmo de Kosaraju resolve isso em $\mathcal{O}(N + M)$, onde $N$ é o número de vértices e $M$ é o número de arestas do grafo. 5 | 6 | O componente fortemente conexo de cada vértice é armazenado no vetor `root`. 7 | A grafo condensado é armazenado no vetor `gc`. 8 | -------------------------------------------------------------------------------- /LaTeX/main.tex: -------------------------------------------------------------------------------- 1 | \input{preamble} 2 | 3 | \begin{document} 4 | \date{\today} 5 | \maketitle 6 | \begin{multicols}{3} 7 | \tableofcontents 8 | \end{multicols} 9 | \clearpage 10 | \begin{multicols}{3} 11 | 12 | % Capítulos principais 13 | \input{chapters/01-cpp/index} 14 | \input{chapters/02-teorico/index} 15 | 16 | % Conteúdo gerado automaticamente 17 | \input{generated/codigos} 18 | 19 | \end{multicols} 20 | \end{document} 21 | -------------------------------------------------------------------------------- /Codigos/Grafos/Matching/Hungaro/README.md: -------------------------------------------------------------------------------- 1 | # [Algoritmo Húngaro](hungarian.cpp) 2 | 3 | Resolve o problema de Matching para uma matriz `A[n][m]`, onde $n \leq m$. 4 | 5 | A implementação minimiza os custos, para maximizar basta multiplicar os pesos por $-1$. 6 | 7 | **A matriz de entrada precisa ser indexada em 1** 8 | 9 | O vetor `result` guarda os pares do matching. 10 | 11 | Complexidade de tempo: $\mathcal{O}(n^2 * m)$ 12 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Floyd-Warshall/README.md: -------------------------------------------------------------------------------- 1 | # [Floyd-Warshall](floyd_warshall.cpp) 2 | 3 | Algoritmo que encontra o menor caminho entre todos os pares de nodos de um grafo com pesos em $\mathcal{O}(N^3)$. 4 | 5 | A ideia do algoritmo é: para cada nodo $k$, passamos por todos os pares de nodos $(i, j)$ e verificamos se é mais curto passar por $k$ para ir de $i$ a $j$ do que o caminho atual de $i$ a $j$. Se for, atualizamos o caminho. -------------------------------------------------------------------------------- /Codigos/Matemática/Floor-and-Mod-Sum-of-Arithmetic-Progressions/README.md: -------------------------------------------------------------------------------- 1 | # [Soma de Floor e Mod de Progressões Aritméticas](floor_and_mod_sum_of_arithmetic_progressions.cpp) 2 | 3 | Fonte: https://github.com/ShahjalalShohag/code-library/blob/main/Number%20Theory/Floor%20Sum%20of%20%20Arithmetic%20Progressions.cpp 4 | 5 | Computa soma de $\bigl\lfloor \frac{a + d\cdot i}{m} \bigr\rfloor$ para $i \in [0, n-1]$ em $\mathcal{O}(\log{m})$. 6 | -------------------------------------------------------------------------------- /PDF/Almanaque.tex: -------------------------------------------------------------------------------- 1 | \input{preamble} 2 | 3 | \begin{document} 4 | \date{\today} 5 | \maketitle 6 | \begin{multicols}{3} 7 | \tableofcontents 8 | \end{multicols} 9 | \clearpage 10 | \begin{multicols}{3} 11 | 12 | % Capítulos principais 13 | \input{chapters/01-cpp/index} 14 | \input{chapters/02-teorico/index} 15 | 16 | % Conteúdo gerado automaticamente 17 | \input{generated/codigos} 18 | 19 | \end{multicols} 20 | \end{document} 21 | -------------------------------------------------------------------------------- /Codigos/String/Manacher/README.md: -------------------------------------------------------------------------------- 1 | # [Manacher](manacher.cpp) 2 | 3 | O algoritmo de manacher encontra todos os palíndromos de uma string em $\mathcal{O}(n)$. Para cada centro, ele conta quantos palíndromos de tamanho ímpar e par existem (nos vetores `d1` e `d2` respectivamente). O método `solve` computa os palíndromos e retorna o número de substrings palíndromas. O método `query` retorna se a substring `s[i...j]` é palíndroma em $\mathcal{O}(1)$. -------------------------------------------------------------------------------- /Codigos/Grafos/Binary-Lifting/Binary-Lifting-Query-2/README.md: -------------------------------------------------------------------------------- 1 | # [Binary Lifting Query 2](binary_lifting_query_nodo2.cpp) 2 | 3 | Basicamente o mesmo que o anterior, mas esse resolve queries em que o `merge` não é necessariamente **comutativo**. Para fins de exemplo, o código está implementado para resolver queries de Kadane (máximo subarray sum) em caminhos. 4 | 5 | Foi usado para passar esse problema: 6 | https://codeforces.com/contest/1843/problem/F2 -------------------------------------------------------------------------------- /Codigos/Matemática/Discrete-Root/README.md: -------------------------------------------------------------------------------- 1 | # [Discrete Root](discrete_root.cpp) 2 | 3 | Fonte: https://github.com/ShahjalalShohag/code-library/blob/main/Number%20Theory/Discrete%20Root.cpp 4 | 5 | Algoritmo que computa a raiz discreta, isto é, para uma equação $x^k \equiv a \pmod{n}$, sendo $n$ primo; computa algum (ou todos) os valores de $x$ 6 | que a satisfazem. 7 | 8 | Complexidade $\approx \mathcal{O}(\sqrt{n} \cdot \log n + \log^6 n) $. 9 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Ordered-Set/ordered_set.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace __gnu_pbds; 5 | 6 | template 7 | using ordered_set = 8 | tree, rb_tree_tag, tree_order_statistics_node_update>; 9 | 10 | template 11 | using ordered_map = tree, rb_tree_tag, tree_order_statistics_node_update>; -------------------------------------------------------------------------------- /Codigos/Grafos/Kruskal/kruskal.cpp: -------------------------------------------------------------------------------- 1 | vector> edges; // {u, v, w} 2 | 3 | void kruskal(int n) { 4 | DSU dsu(n); // DSU da seção Estruturas de Dados 5 | 6 | sort(edges.begin(), edges.end(), [](auto a, auto b) { 7 | return get<2>(a) < get<2>(b); 8 | }); 9 | 10 | for (auto [u, v, w] : edges) { 11 | if (dsu.unite(u, v)) { 12 | // edge u-v is in the MST 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Dijkstra/README.md: -------------------------------------------------------------------------------- 1 | # [Dijkstra](dijkstra.cpp) 2 | 3 | Computa o menor caminho entre nodos de um grafo com pesos quaisquer nas arestas. 4 | 5 | Dado um nodo $s$, computa o menor caminho de $s$ para todos os outros nodos em $\mathcal{O}((V + E) \cdot \log E)$. 6 | 7 | Muito semelhante a uma BFS, mas usa uma fila de prioridade ao invés de uma fila comum. 8 | 9 | **Importante**: O grafo não pode conter arestas de peso negativo. -------------------------------------------------------------------------------- /Codigos/Matemática/Polinomios/README.md: -------------------------------------------------------------------------------- 1 | # [Operações em Polinômios](polinomio.cpp) 2 | 3 | Fonte: https://github.com/ShahjalalShohag/code-library/blob/main/Math/Polynomial.cpp 4 | 5 | Estrutura de polinômio, possui diversas operações; entre elas: divisão, módulo, multiplicação, log, etc. 6 | Além de algoritmos como Multipoint Evaluation (eval). 7 | 8 | Depende de ntt.cpp e mint.cpp. 9 | 10 | Testado apenas em https://codeforces.com/gym/105949/problem/G 11 | -------------------------------------------------------------------------------- /LaTeX/chapters/02-teorico/index.tex: -------------------------------------------------------------------------------- 1 | \section{Teórico} 2 | 3 | \input{chapters/02-teorico/definicoes} 4 | \input{chapters/02-teorico/primos} 5 | \input{chapters/02-teorico/operadores-lineares} 6 | \input{chapters/02-teorico/sequencias-numericas} 7 | \input{chapters/02-teorico/analise-combinatoria} 8 | \input{chapters/02-teorico/teoria-dos-numeros} 9 | \input{chapters/02-teorico/markov-chains} 10 | \input{chapters/02-teorico/problema-da-realizacao-de-grafos} 11 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Crivo/Crivo/README.md: -------------------------------------------------------------------------------- 1 | # [Crivo de Eratóstenes](sieve.cpp) 2 | 3 | Crivo de Eratóstenes para encontrar os primos até um limite $P$. O `vector is_prime` é um vetor que diz se um número é primo ou não. A complexidade é $\mathcal{O}(P \log (\log P))$. 4 | 5 | **Observações**: 6 | 7 | - Para aplicações mais complexas ou para fatorar um número, consulte o Crivo Linear. 8 | - Não se esqueça de chamar `Sieve::build()` antes de usar. 9 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Operation-Queue/README.md: -------------------------------------------------------------------------------- 1 | # [Operation Queue](op_queue.cpp) 2 | 3 | Fila que armazena o resultado do operatório dos itens (ou seja, dado uma fila, responde qual é o elemento mínimo, por exemplo). A fila possui a operação `get` que retorna o resultado do operatório dos itens da fila em $\mathcal{O}(1)$ amortizado. Chamar o método `get` em uma fila vazia é indefinido. 4 | 5 | **Obs**: usa a estrutura Operation Stack (também descrita nesse Almanaque). 6 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU/README.md: -------------------------------------------------------------------------------- 1 | # [DSU](dsu.cpp) 2 | 3 | Estrutura que mantém uma coleção de conjuntos e permite as operações de unir dois conjuntos e verificar em qual conjunto um elemento está, ambas em $\mathcal{O}(1)$ amortizado. O método `find` retorna o representante do conjunto que contém o elemento, e o método `unite` une os conjuntos que contém os elementos dados, retornando `true` se eles estavam em conjuntos diferentes e `false` caso contrário. 4 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Operation-Deque/README.md: -------------------------------------------------------------------------------- 1 | # [Operation Queue](op_deque.cpp) 2 | 3 | Deque que armazena o resultado do operatório dos itens (ou seja, dado um deque, responde qual é o elemento mínimo, por exemplo). O deque possui a operação `get` que retorna o resultado do operatório dos itens do deque em $\mathcal{O}(1)$ amortizado. Chamar o método `get` em um deque vazia é indefinido. 4 | 5 | **Obs**: usa a estrutura Operation Stack (também descrita nesse Almanaque). 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/FFT/README.md: -------------------------------------------------------------------------------- 1 | # [Transformada Rápida de Fourier](fft.cpp) 2 | 3 | Algoritmo que computa a Transformada Rápida de Fourier para convolução de polinômios. 4 | 5 | Computa convolução (multiplicação) de polinômios em $\mathcal{O}(N \cdot \log N)$, sendo $N$ a soma dos graus dos polinômios. 6 | 7 | Testado e sem erros de precisão com polinômios de grau até $3 * 10^5$ e constantes até $10^6$. Para convolução de inteiros sem erro de precisão, consultar a seção de NTT. 8 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Teste-Primalidade/Miller-Rabin/README.md: -------------------------------------------------------------------------------- 1 | # [Miller-Rabin](miller_rabin.cpp) 2 | 3 | Teste de primalidade Miller-Rabin. A função `MillerRabin::prime(X)` retorna verdadeiro se $X$ é primo e falso caso contrário. O teste é determinístico para para números até $2^{64}$. A complexixade do algoritmo é $\mathcal{O}(\log X)$, considerando multiplicação e exponenciação constantes. 4 | 5 | Para números até $2^{32}$, é suficiente usar `primes[] = {2, 3, 5, 7}`. -------------------------------------------------------------------------------- /Codigos/String/Lyndon/min_cyclic_shift.cpp: -------------------------------------------------------------------------------- 1 | string min_cyclic_shift(string s) { 2 | s += s; 3 | int n = s.size(); 4 | int i = 0, ans = 0; 5 | while (i < n / 2) { 6 | ans = i; 7 | int j = i + 1, k = i; 8 | while (j < n && s[k] <= s[j]) { 9 | if (s[k] < s[j]) k = i; 10 | else k++; 11 | j++; 12 | } 13 | while (i <= k) i += j - k; 14 | } 15 | return s.substr(ans, n / 2); 16 | } 17 | -------------------------------------------------------------------------------- /Codigos/Grafos/Binary-Lifting/Binary-Lifting-LCA/README.md: -------------------------------------------------------------------------------- 1 | # [Binary Lifting](binary_lifting_lca.cpp) 2 | 3 | Usa uma matriz para precomputar os ancestrais de um nodo, em que `up[u][i]` é o $2 ^ i$-ésimo ancestral de `u`. A construção é $\mathcal{O}(n \log n)$, e é possível consultar pelo $k$-ésimo ancestral de um nodo e pelo **LCA** de dois nodos em $\mathcal{O}(\log n)$. 4 | 5 | **LCA**: Lowest Common Ancestor, o LCA de dois nodos $u$ e $v$ é o nodo mais profundo que é ancestral de ambos. 6 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/Mo/Mo/README.md: -------------------------------------------------------------------------------- 1 | # [Mo](mo.cpp) 2 | 3 | Resolve queries complicadas Offline de forma rápida. 4 | 5 | É preciso manter uma estrutura que adicione e remova elementos nas extremidades de um range (tipo janela). 6 | 7 | A complexidade do `run` é $\mathcal{O}(Q * B + N^2/B)$, onde $B$ é o tamanho do bloco. 8 | 9 | Para $B = \sqrt{N}$, a complexidade é $\mathcal{O}((N + Q) * \sqrt{N})$. 10 | 11 | Para $B = N / \sqrt Q$, a complexidade é $\mathcal{O}(N * \sqrt{Q})$. 12 | -------------------------------------------------------------------------------- /Codigos/Grafos/Centroids/Centroid/README.md: -------------------------------------------------------------------------------- 1 | # [Centroid](find_centroids.cpp) 2 | 3 | Algoritmo que encontra os dois centroides de uma árvore em $\mathcal{O}(N)$. 4 | 5 | **Definição**: O centroide de uma árvore é o nodo tal que, ao ser removido, divide a árvore em subárvores com no máximo metade dos nodos da árvore original. Em outras palavras, se a árvore tem tamanho $N$, todas as subárvores geradas pela remoção do centroide têm tamanho no máximo $\frac{N}{2}$. Uma árvore pode ter até dois centróides. 6 | -------------------------------------------------------------------------------- /Codigos/Grafos/Stoer–Wagner-Min-Cut/README.md: -------------------------------------------------------------------------------- 1 | # [Stoer-Wagner](stoer_wagner.cpp) 2 | 3 | Algortimo de Stoer-Wagner para encontrar o corte mínimo de um grafo. 4 | 5 | O algoritmo de Stoer-Wagner é um algoritmo para resolver o problema de corte mínimo em grafos não direcionados com pesos não negativos. A ideia essencial deste algoritmo é encolher o grafo mesclando os nodos mais intensos até que o grafo contenha apenas dois conjuntos de nodos combinados 6 | 7 | Complexidade de tempo: $\mathcal{O}(V^3)$ 8 | -------------------------------------------------------------------------------- /Codigos/Extra/Unordered-Custom-Hash/README.md: -------------------------------------------------------------------------------- 1 | # [Custom Hash](custom_hash.cpp) 2 | 3 | As funções de hash padrão do `unordered_map` e `unordered_set` são muito propícias a colisões (principalmente se o setter da questão criar casos de teste pensando nisso). 4 | Para evitar isso, é possível criar uma função de hash customizada. 5 | 6 | Entretanto, é bem raro ser necessário usar isso. Geralmente o fator $\mathcal{O}(\log n)$ de um `map` é suficiente. 7 | 8 | Exemplo de uso: `unordered_map mp;` -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Treap/README.md: -------------------------------------------------------------------------------- 1 | # [Treap](treap.cpp) 2 | 3 | Uma árvore de busca binária balanceada. Se não quiser ter elementos repetidos, basta fazer `treap::setify = true`. 4 | 5 | - `insert(X)`: insere um elemento $X$ na árvore em $\mathcal{O}(\log N)$ 6 | - `remove(X)`: remove uma ocorrência de $X$ na árvore, e retorna `false` caso não tenha nenhuma ocorrência de $X$ na árvore em $\mathcal{O}(\log N)$. 7 | - `find(X)`: retorna `true` se $X$ aparece pelo menos uma vez na árvore em $\mathcal{O}(\log N)$. 8 | -------------------------------------------------------------------------------- /Codigos/Extra/Stress-Test/stress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | g++ -O2 gen.cpp -o gen # pode fazer o gerador em python se preferir 5 | g++ -O2 brute.cpp -o brute 6 | g++ -O2 code.cpp -o code 7 | 8 | for((i = 1; ; ++i)); do 9 | ./gen $i > in 10 | ./code < in > out 11 | ./brute < in > ok 12 | diff -w out ok || break 13 | echo "Passed test: " $i 14 | done 15 | 16 | echo "WA no seguinte teste:" 17 | cat in 18 | echo "Sua resposta eh:" 19 | cat out 20 | echo "A resposta correta eh:" 21 | cat ok -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Iterativa/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree Iterativa](itseg_tree.cpp) 2 | 3 | Implementação padrão de Segment Tree, suporta operações de consulta em intervalo e update pontual. Está implementada para soma, mas pode ser facilmente modificada para outras operações. A construção é $\mathcal{O}(n)$ e as operações de consulta e update são $\mathcal{O}(\log n)$. 4 | 5 | Essa implementação é iterativa, o que a torna mais eficiente que a recursiva, além de ser mais fácil de implementar. 6 | -------------------------------------------------------------------------------- /Codigos/Grafos/Inverse-Graph/inverse_graph.cpp: -------------------------------------------------------------------------------- 1 | set nodes; 2 | vector> adj; 3 | 4 | void bfs(int s) { 5 | queue f; 6 | f.push(s); 7 | nodes.erase(s); 8 | set aux; 9 | while (!f.empty()) { 10 | int x = f.front(); 11 | f.pop(); 12 | for (int y : nodes) 13 | if (adj[x].count(y) == 0) aux.insert(y); 14 | for (int y : aux) { 15 | f.push(y); 16 | nodes.erase(y); 17 | } 18 | aux.clear(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Pollard-Rho/README.md: -------------------------------------------------------------------------------- 1 | # [Pollard Rho](pollard_rho.cpp) 2 | 3 | Algoritmo de Pollard Rho. A função `PollardRho::rho(X)` retorna um fator não trivial de $X$. Um fator não trivial é um fator que não é $1$ nem $X$. A complexidade esperada do algoritmo no pior caso é $\mathcal{O}(\sqrt[4]{X})$ (geralmente é mais rápido que isso). 4 | 5 | **Obs**: cuidado para não passar um número primo ou o número $1$ para a função `rho`, o comportamente é indefinido (provavelmente entra em loop e não retorna nunca). 6 | -------------------------------------------------------------------------------- /Codigos/String/Prefix-Function-KMP/KMP/README.md: -------------------------------------------------------------------------------- 1 | # [KMP](kmp.cpp) 2 | 3 | O algoritmo de Knuth-Morris-Pratt (KMP) computa em $\mathcal{O}(|s|)$ a Prefix Function de uma string, cuja definição é dada por: 4 | 5 | $$ p[i] = \max\{k \mid s[0,k) = s(i-k,i]\} $$ 6 | 7 | Em outras palavras, $p[i]$ é o tamanho do maior prefixo de $s$ que é sufixo próprio de $s[0,i]$. 8 | 9 | O KMP é útil para pattern matching, ou seja, encontrar todas as ocorrências de uma string $t$ em uma string $s$, como faz a função `matching` em $\mathcal{O}(|s| + |t|)$. -------------------------------------------------------------------------------- /containers/latex.Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE=python:3.11-slim 2 | FROM ${BASE_IMAGE} 3 | 4 | ARG APT_PACKAGES="texlive-latex-base texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended texlive-lang-portuguese lmodern latexmk rubber make git" 5 | 6 | ENV DEBIAN_FRONTEND=noninteractive \ 7 | PIP_NO_CACHE_DIR=1 8 | 9 | RUN apt-get update && \ 10 | apt-get install -y --no-install-recommends ${APT_PACKAGES} && \ 11 | apt-get clean && \ 12 | rm -rf /var/lib/apt/lists/* 13 | 14 | WORKDIR /workspace 15 | -------------------------------------------------------------------------------- /Codigos/Grafos/Centro-e-Diametro/README.md: -------------------------------------------------------------------------------- 1 | # Centro e Diâmetro 2 | 3 | Algoritmo que encontra o centro e o diâmetro de um grafo em $\mathcal{O}(N + M)$ com duas BFS. 4 | 5 | **Definição**: O centro de um grafo é igual ao subconjunto de nodos com excentricidade mínima. A excentricidade de um nodo é a maior distância dele para qualquer outro nodo. Em outras palavras, pra um nodo ser centro do grafo, ele deve minimizar a maior distância para qualquer outro nodo. 6 | 7 | O diâmetro de um grafo é a maior distância entre dois nodos quaisquer. 8 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/Busca-Ternaria/busca_ternaria.cpp: -------------------------------------------------------------------------------- 1 | 2 | double eval(double mid) { 3 | // implement the evaluation 4 | } 5 | 6 | double ternary_search(double l, double r) { 7 | int k = 100; 8 | while (k--) { 9 | double step = (l + r) / 3; 10 | double mid_1 = l + step; 11 | double mid_2 = r - step; 12 | 13 | // minimizing. To maximize use >= to 14 | // compare 15 | if (eval(mid_1) <= eval(mid_2)) r = mid_2; 16 | else l = mid_1; 17 | } 18 | return l; 19 | } 20 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/BFS/bfs.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | 3 | int n; 4 | vector adj[N]; 5 | 6 | vector bfs(int s) { 7 | vector dist(n, -1); 8 | queue q; 9 | dist[s] = 0; 10 | q.emplace(s); 11 | while (!q.empty()) { 12 | int u = q.front(); 13 | q.pop(); 14 | for (auto v : adj[u]) { 15 | if (dist[v] == -1) { 16 | dist[v] = dist[u] + 1; 17 | q.emplace(v); 18 | } 19 | } 20 | } 21 | return dist; 22 | } -------------------------------------------------------------------------------- /Codigos/Paradigmas/Convex-Hull-Trick/README.md: -------------------------------------------------------------------------------- 1 | # Convex Hull Trick 2 | 3 | Otimização de DP onde se mantém as retas que formam um Convex Hull em uma estrutura que permite consultar qual o melhor valor para um determinado $x$. 4 | 5 | Só funciona quando as retas são monotônicas. Caso não sejam, usar LiChao Tree para guardar as retas. 6 | 7 | Complexidade de tempo: 8 | 9 | - Inserir reta: $\mathcal{O}(1)$ amortizado 10 | - Consultar $x$: $\mathcal{O}(\log(N))$ 11 | - Consultar $x$ quando $x$ tem crescimento monotônico: $\mathcal{O}(1)$ 12 | -------------------------------------------------------------------------------- /Codigos/String/Lyndon/README.md: -------------------------------------------------------------------------------- 1 | # Lyndon Factorization 2 | 3 | Strings em decomposição única em subcadeias que são ordenadas lexicograficamente e não podem ser mais reduzidas. 4 | 5 | ## [Duval](duval.cpp) 6 | 7 | Gera a Lyndon Factorization de uma string 8 | 9 | * Complexidade de tempo: $\mathcal{O}(N)$ 10 | 11 | ## [Min Cyclic Shift](min_cyclic_shift.cpp) 12 | 13 | Gera a menor rotação circular da string original que pode ser obtida por meio de deslocamentos cíclicos dos caracteres. 14 | 15 | * Complexidade de tempo: $\mathcal{O}(N)$ -------------------------------------------------------------------------------- /Codigos/String/Lyndon/duval.cpp: -------------------------------------------------------------------------------- 1 | vector duval(string const &s) { 2 | int n = s.size(); 3 | int i = 0; 4 | vector factorization; 5 | while (i < n) { 6 | int j = i + 1, k = i; 7 | while (j < n && s[k] <= s[j]) { 8 | if (s[k] < s[j]) k = i; 9 | else k++; 10 | j++; 11 | } 12 | while (i <= k) { 13 | factorization.push_back(s.substr(i, j - k)); 14 | i += j - k; 15 | } 16 | } 17 | return factorization; 18 | } 19 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Operation-Stack/op_stack.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct op_stack { 3 | vector> st; 4 | T get() { return st.back().second; } 5 | T top() { return st.back().first; } 6 | T bottom() { return st.front().first; } 7 | void push(T x) { 8 | auto snd = st.empty() ? x : OP(st.back().second, x); 9 | st.push_back({x, snd}); 10 | } 11 | void pop() { st.pop_back(); } 12 | bool empty() { return st.empty(); } 13 | int size() { return (int)st.size(); } 14 | }; -------------------------------------------------------------------------------- /Codigos/Extra/Unordered-Custom-Hash/custom_hash.cpp: -------------------------------------------------------------------------------- 1 | struct custom_hash { 2 | static uint64_t splitmix64(uint64_t x) { 3 | x += 0x9e3779b97f4a7c15; 4 | x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; 5 | x = (x ^ (x >> 27)) * 0x94d049bb133111eb; 6 | return x ^ (x >> 31); 7 | } 8 | 9 | size_t operator()(uint64_t x) const { 10 | static const uint64_t FIXED_RANDOM = 11 | chrono::steady_clock::now().time_since_epoch().count(); 12 | return splitmix64(x + FIXED_RANDOM); 13 | } 14 | }; -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Floyd-Warshall/floyd_warshall.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e3 + 5; 2 | const ll INF = 1e18; 3 | int n; 4 | 5 | ll adj[N][N]; // adj[u][v] = peso da aresta u-v, INF se não existe 6 | ll dist[N][N]; 7 | 8 | void floydwarshall() { 9 | for (int u = 0; u < n; u++) 10 | for (int v = 0; v < n; v++) dist[u][v] = adj[u][v]; 11 | for (int k = 0; k < n; k++) { 12 | for (int i = 0; i < n; i++) 13 | for (int j = 0; j < n; j++) 14 | dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); 15 | } 16 | } -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU/dsu.cpp: -------------------------------------------------------------------------------- 1 | struct DSU { 2 | vector par, sz; 3 | void build(int n) { 4 | par.assign(n, 0); 5 | iota(par.begin(), par.end(), 0); 6 | sz.assign(n, 1); 7 | } 8 | int find(int a) { return a == par[a] ? a : par[a] = find(par[a]); } 9 | bool unite(int a, int b) { 10 | a = find(a), b = find(b); 11 | if (a == b) return false; 12 | if (sz[a] < sz[b]) swap(a, b); 13 | par[b] = a; 14 | sz[a] += sz[b]; 15 | return true; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/Offline-DSU/README.md: -------------------------------------------------------------------------------- 1 | # [DSU Offline](offline_dsu.cpp) 2 | 3 | Algoritmo que utiliza o DSU com Rollback e Bipartido que permite adição e **remoção** de arestas. O algoritmo funciona de maneira offline, recebendo previamente todas as operações de adição e remoção de arestas, bem como todas as perguntas (de qualquer tipo, conectividade, bipartição, etc), e retornando as respostas para cada pergunta no retorno do método `solve`. Complexidade total $\mathcal{O}(Q \cdot (\log Q + \log N))$, onde $Q$ é o número de operações realizadas e $N$ é o número de nodos. 4 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/XOR-Trie/README.md: -------------------------------------------------------------------------------- 1 | # [XOR Trie](xor_trie.cpp) 2 | 3 | Uma Trie que armazena os números em binario (do bit mais significativo para o menos). Permite realizar inserção de um número $X$ em $\mathcal{O}(\log X)$. O inteiro `bits` no template da estrutura é a quantidade bits dos números você deseja considerar. 4 | 5 | O método `max_xor(X)` retorna o resultado do maior XOR de $X$ com algum número contido na Trie e `min_xor(X)` resultado do menor XOR de $X$ com algum número contido na Trie. Note que o valor $X$ não precisa estar na Trie. Ambos os métodos são $\mathcal{O}(\log X)$. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/NTT/NTT-Big-Modulo/README.md: -------------------------------------------------------------------------------- 1 | # [NTT Big Mod](big_ntt.cpp) 2 | 3 | NTT usada para computar a multiplicação de polinômios com coeficientes inteiros módulo um número primo grande. A ideia na maioria dos casos é computar a multiplicação como se não houvesse módulo, por isso usamos um módulo grande. 4 | 5 | Uma forma de fazer essa NTT com módulo grande é usar o módulo grande que está na seção NTT. 6 | 7 | A forma usada nesse código é usar dois módulos na ordem de $10^9$ e fazer a multiplicação com eles. E depois usar o Teorema do Resto Chinês para achar o resultado módulo o produto dos módulos. -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/LCM-Convolution/lcm_convolution.cpp: -------------------------------------------------------------------------------- 1 | vector lcm_convolution(vector A, vector B) { 2 | int N = (int)max(A.size(), B.size()); 3 | A.resize(N + 1); 4 | B.resize(N + 1); 5 | vector C(N + 1), a(N + 1), b(N + 1); 6 | for (int i = 1; i <= N; i++) { 7 | for (int j = i; j <= N; j += i) { 8 | a[j] += A[i]; 9 | b[j] += B[i]; 10 | } 11 | C[i] = a[i] * b[i]; 12 | } 13 | for (int i = 1; i <= N; i++) 14 | for (int j = 2 * i; j <= N; j += i) C[j] -= C[i]; 15 | return C; 16 | } 17 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU-Bipartido/README.md: -------------------------------------------------------------------------------- 1 | # [DSU Bipartido](bipartite_dsu.cpp) 2 | 3 | DSU que mantém se um conjunto é bipartido (visualize os conjuntos como componentes conexas de um grafo e os elementos como nodos). O método $unite$ adiciona uma aresta entre os dois elementos dados, e retorna `true` se os elementos estavam em conjuntos diferentes (componentes conexas diferentes) e `false` caso contrário. O método `bipartite` retorna `true` se o conjunto (componente conexa) que contém o elemento dado é bipartido e `false` caso contrário. Todas as operações são $\mathcal{O}(\log N)$. 4 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Dial/README.md: -------------------------------------------------------------------------------- 1 | # [Dial](dial.cpp) 2 | 3 | Computa o menor caminho entre nodos de um grafo com pesos nas arestas. 4 | 5 | Útil quando o maior peso de uma aresta $D$ não é muito grande (inutilizável se $D$ puder ser até $10^9$, vide a 6 | complexidade abaixo). 7 | 8 | Dado um nodo $s$, computa o menor caminho de $s$ para todos os outros nodos em $\mathcal{O}(D \cdot V + E)$. 9 | 10 | Muito semelhante a uma BFS, mas simula $D+1$ filas, uma para cada distância a cada passo do algoritmo, ao invés de uma só fila. 11 | 12 | **Importante**: O grafo não pode conter arestas de peso negativo. 13 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/GCD-Convolution/gcd_convolution.cpp: -------------------------------------------------------------------------------- 1 | vector gcd_convolution(vector A, vector B) { 2 | int N = (int)max(A.size(), B.size()); 3 | A.resize(N + 1); 4 | B.resize(N + 1); 5 | vector C(N + 1); 6 | for (int i = 1; i <= N; i++) { 7 | mint a = 0; 8 | mint b = 0; 9 | for (int j = i; j <= N; j += i) { 10 | a += A[j]; 11 | b += B[j]; 12 | } 13 | C[i] = a * b; 14 | } 15 | for (int i = N; i >= 1; i--) 16 | for (int j = 2 * i; j <= N; j += i) C[i] -= C[j]; 17 | return C; 18 | } 19 | -------------------------------------------------------------------------------- /Codigos/String/Trie/trie.cpp: -------------------------------------------------------------------------------- 1 | struct trie { 2 | map trie[100005]; 3 | int value[100005]; 4 | int n_nodes = 0; 5 | void insert(string &s, int v) { 6 | int id = 0; 7 | for (char c : s) { 8 | if (!trie[id].count(c)) trie[id][c] = ++n_nodes; 9 | id = trie[id][c]; 10 | } 11 | value[id] = v; 12 | } 13 | int get_value(string &s) { 14 | int id = 0; 15 | for (char c : s) { 16 | if (!trie[id].count(c)) return -1; 17 | id = trie[id][c]; 18 | } 19 | return value[id]; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Beats/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree Beats](seg_tree_beats.cpp) 2 | 3 | Segment Tree que suporta update de máximo em range, update de mínimo em range, update de soma em range, e query de soma em range. A construção é $\mathcal{O}(n)$ e as operações de consulta e update são $\mathcal{O}(\log^2 n)$. 4 | 5 | Update de máximo em um range $[L, R]$ passando um valor $X$, significa para cada $i$ tal que $L \le i \le R$, fazer a operação $a[i] = max(a[i], X)$. Update de mínimo é análogo. 6 | 7 | **Obs**: Se não usar o update de soma, a complexidade é das operações é $\mathcal{O}(\log n)$ 8 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/Busca-Ternaria/busca_ternaria_discreta.cpp: -------------------------------------------------------------------------------- 1 | 2 | long long eval(long long mid) { 3 | // implement the evaluation 4 | } 5 | 6 | long long discrete_ternary_search(long long l, long long r) { 7 | long long ans = -1; 8 | r--; // to not space r 9 | while (l <= r) { 10 | long long mid = (l + r) / 2; 11 | 12 | // minimizing. To maximize use >= to 13 | // compare 14 | if (eval(mid) <= eval(mid + 1)) { 15 | ans = mid; 16 | r = mid - 1; 17 | } else { 18 | l = mid + 1; 19 | } 20 | } 21 | return ans; 22 | } 23 | -------------------------------------------------------------------------------- /Codigos/Matemática/Floor-Values/README.md: -------------------------------------------------------------------------------- 1 | # [Floor Values](floor_values.cpp) 2 | 3 | Código para encontrar todos os $\mathcal{O}(\sqrt{n})$ valores distintos de $\left\lfloor \frac{n}{i} \right\rfloor$ para $i = 1, 2, \ldots, n$. 4 | 5 | Útil para computar, dentre outras coisas, os seguintes somatórios: 6 | 7 | - Somatório de $\left\lfloor \frac{n}{i} \right\rfloor$ para $i = 1, 2, \ldots, n$. 8 | 9 | - Somatório de $\sigma(i)$ para $i = 1, 2, \ldots, n$, onde $\sigma(i)$ é a soma dos divisores de $i$. 10 | - Usa o fato de que um número $i$ é divisor de exatamente $\left\lfloor \frac{n}{i} \right\rfloor$ números entre $1$ e $n$. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Sparse-Table/Sparse-Table/README.md: -------------------------------------------------------------------------------- 1 | # [Sparse Table](sparse_table.cpp) 2 | 3 | Precomputa em $\mathcal{O}(n \log n)$ uma tabela que permite responder consultas de mínimo/máximo em intervalos em $\mathcal{O}(1)$. 4 | 5 | A implementação atual é para mínimo, mas pode ser facilmente modificada para máximo ou outras operações. 6 | 7 | A restrição é de que a operação deve ser associativa e idempotente (ou seja, $f(x, x) = x$). 8 | 9 | Exemplos de operações idempotentes: `min`, `max`, `gcd`, `lcm`. 10 | 11 | Exemplos de operações não idempotentes: `soma`, `xor`, `produto`. 12 | 13 | **Obs**: não suporta updates. 14 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | UseTab: Never 3 | IndentWidth: 4 4 | TabWidth: 4 5 | ColumnLimit: 90 6 | AllowShortBlocksOnASingleLine: Always 7 | AllowShortFunctionsOnASingleLine: All 8 | AllowShortIfStatementsOnASingleLine: AllIfsAndElse 9 | AllowShortLambdasOnASingleLine: All 10 | AllowShortLoopsOnASingleLine: true 11 | RemoveBracesLLVM: true 12 | RemoveParentheses: ReturnStatement 13 | RemoveSemicolon: true 14 | NamespaceIndentation: All 15 | FixNamespaceComments: false 16 | BinPackArguments: false 17 | BinPackParameters: false 18 | SpaceInEmptyBlock: true 19 | AlignAfterOpenBracket: BlockIndent 20 | AlwaysBreakTemplateDeclarations: true 21 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Interval-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [Interval Tree](interval_tree.cpp) (Autoral) 2 | 3 | **Por Rafael Granza de Mello** 4 | 5 | Estrutura que trata intersecções de intervalos. 6 | 7 | Capaz de retornar todos os intervalos que intersectam $[L, R]$. Contém métodos `insert({L, R, ID})`, `erase({L, R, ID})`, `overlaps(L, R)` e `find({L, R, ID})`. É necessário inserir e apagar indicando tanto os limites quanto o ID do intervalo. Todas as operações são $\mathcal{O}(\log n)$, exceto `overlaps` que é $\mathcal{O}(k + \log n)$, onde $k$ é o número de intervalos que intersectam $[L, R]$. Também podem ser usadas as operações padrões de um `std::set` 8 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Bellman-Ford/bellman_ford.cpp: -------------------------------------------------------------------------------- 1 | const ll INF = 1e18; 2 | 3 | int n; 4 | vector> edges; 5 | 6 | vector bellman_ford(int s) { 7 | vector dist(n, INF); 8 | dist[s] = 0; 9 | for (int i = 0; i < n; i++) { 10 | for (auto [u, v, w] : edges) 11 | if (dist[u] < INF) dist[v] = min(dist[v], dist[u] + w); 12 | } 13 | for (int i = 0; i < n; i++) { 14 | for (auto [u, v, w] : edges) 15 | if (dist[u] < INF && dist[u] + w < dist[v]) dist[v] = -INF; 16 | } 17 | // dist[u] = -INF se tem um ciclo negativo que chega em u 18 | return dist; 19 | } 20 | -------------------------------------------------------------------------------- /Codigos/String/Suffix-Array/README.md: -------------------------------------------------------------------------------- 1 | # [Suffix Array](suffix_array.cpp) 2 | 3 | Estrutura que conterá inteiros que representam os índices iniciais de todos os sufixos ordenados de uma determinada string. 4 | 5 | Também constrói a tabela LCP (Longest Common Prefix). 6 | 7 | - `sa[i]` = Índice inicial do i-ésimo menor sufixo. 8 | - `ra[i]` = Rank do sufixo que começa em `i`. 9 | - `LCP[i]` = Comprimento do maior prefixo comum entre os sufixos `sa[i]` e `sa[i-1]`. 10 | 11 | * Complexidade de tempo (Pré-Processamento): $\mathcal{O}(|S| \cdot \log(|S|))$ 12 | * Complexidade de tempo (Contar ocorrências de $S$ em $T$): $\mathcal{O}(|S| \cdot \log(|T|))$ 13 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/01-BFS/bfs01.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | const int INF = 1e9; 3 | 4 | int n; 5 | vector> adj[N]; 6 | 7 | vector bfs01(int s) { 8 | vector dist(n, INF); 9 | deque q; 10 | dist[s] = 0; 11 | q.emplace_back(s); 12 | while (!q.empty()) { 13 | int u = q.front(); 14 | q.pop_front(); 15 | for (auto [w, v] : adj[u]) { 16 | if (dist[u] + w < dist[v]) { 17 | dist[v] = dist[u] + w; 18 | if (w == 0) q.push_front(v); 19 | else q.push_back(v); 20 | } 21 | } 22 | } 23 | return dist; 24 | } -------------------------------------------------------------------------------- /Codigos/String/Prefix-Function-KMP/Automato-KMP/README.md: -------------------------------------------------------------------------------- 1 | # [Autômato de KMP](aut_kmp.cpp) 2 | 3 | O autômato de KMP computa em $\mathcal{O}(|s| \cdot \Sigma)$ a função de transição de uma string, que é definida por: 4 | 5 | $$ nxt[i][c] = \max\{k \mid s[0,k) = s(i-k,i-1]c\} $$ 6 | 7 | Em outras palavras, $nxt[i][c]$ é o tamanho do maior prefixo de $s$ que é sufixo de $s[0,i-1]c$. 8 | 9 | O autômato de KMP é útil para mútiplos pattern matchings, ou seja, dado um padrão $t$, encontrar todas as ocorrências de $t$ em várias strings $s_1, s_2, \dots, s_k$, em $\mathcal{O}(|t| + \sum |s_i|)$. O método `matching` faz isso. 10 | 11 | **Obs**: utiliza o código do KMP. -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Crivo/Crivo-Linear/README.md: -------------------------------------------------------------------------------- 1 | # [Crivo de Eratóstenes Linear](linear_sieve.cpp) 2 | 3 | Crivo de Eratóstenes para encontrar os primos até um limite $P$, mas com complexidade $\mathcal{O}(P)$. 4 | 5 | - `vector is_prime` é um vetor que diz se um número é primo ou não. 6 | - `int cnt` é o número de primos encontrados. 7 | - `int primes[P]` é um vetor com `cnt` os primos encontrados. 8 | - `int lpf[P]` é o menor fator primo de cada número (usado para fatoração). 9 | 10 | A função `Sieve::factorize()` fatora um número $N$ em tempo $\mathcal{O}(\log N)$. 11 | 12 | **Obs**: Não esquecer de chamar `Sieve::build()` antes de usar. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Fenwick-Tree/Fenwick/README.md: -------------------------------------------------------------------------------- 1 | # [Fenwick Tree](fenwick_tree.cpp) 2 | 3 | Árvore de Fenwick (ou BIT) é uma estrutura de dados que permite atualizações pontuais e consultas de prefixos em um vetor em $\mathcal{O}(\log n)$. A implementação abaixo é 0-indexada (é mais comum encontrar a implementação 1-indexada). A consulta em ranges arbitrários com o método `query` é possível para qualquer operação inversível, como soma, XOR, multiplicação, etc. A implementação abaixo é para soma, mas é fácil adaptar para outras operações. O método `update` soma $d$ à posição $i$ do vetor, enquanto o método `updateSet` substitue o valor da posição $i$ do vetor por $d$. 4 | -------------------------------------------------------------------------------- /Codigos/Grafos/Pontes/Componentes-Aresta-Biconexas/README.md: -------------------------------------------------------------------------------- 1 | # [Componentes Aresta Biconexas](ebcc_components.cpp) 2 | 3 | Código que acha componentes aresta-biconexas, que são componentes que para se desconectar é necessário remover pelo menos duas arestas. Para obter essas componentes, basta achar as pontes e contrair o resto do grafo, o resultado é uma árvore em que as arestas são as pontes do grafo original. 4 | 5 | Esse algoritmo acha as pontes e constrói o grafo comprimido em $\mathcal{O}(V + E)$. Pontes são arestas cuja remoção aumenta o número de componentes conexas do grafo. 6 | 7 | No código, `ebcc[u]` é o índice da componente aresta-biconexa a qual o vértice `u` pertence. -------------------------------------------------------------------------------- /Codigos/Matemática/Floor-and-Mod-Sum-of-Arithmetic-Progressions/floor_and_mod_sum_of_arithmetic_progressions.cpp: -------------------------------------------------------------------------------- 1 | ll sumsq(ll n) { return n / 2 * ((n - 1) | 1); } 2 | // \sum_{i = 0}^{n - 1}{(a + d * i) / m}, O(log m) 3 | ll floor_sum(ll a, ll d, ll m, ll n) { 4 | ll res = d / m * sumsq(n) + a / m * n; 5 | d %= m; 6 | a %= m; 7 | if (!d) return res; 8 | ll to = (n * d + a) / m; 9 | return res + (n - 1) * to - floor_sum(m - 1 - a, m, d, to); 10 | } 11 | // \sum_{i = 0}^{n - 1}{(a + d * i) % m} 12 | ll mod_sum(ll a, ll d, ll m, ll n) { 13 | a = ((a % m) + m) % m; 14 | d = ((d % m) + m) % m; 15 | return n * a + d * sumsq(n) - m * floor_sum(a, d, m, n); 16 | } 17 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Fatores/Fatoração-Rápida/fast_factorize.cpp: -------------------------------------------------------------------------------- 1 | vector factorize(ll y) { 2 | vector f; 3 | if (y == 1) return f; 4 | auto dfs = [&](auto &&self, ll x) -> void { 5 | if (x == 1) return; 6 | if (x < Sieve::P) { 7 | auto fs = Sieve::factorize(x); 8 | f.insert(f.end(), fs.begin(), fs.end()); 9 | } else if (MillerRabin::prime(x)) { 10 | f.push_back(x); 11 | } else { 12 | ll d = PollardRho::rho(x); 13 | self(self, d); 14 | self(self, x / d); 15 | } 16 | }; 17 | dfs(dfs, y); 18 | sort(f.begin(), f.end()); 19 | return f; 20 | } 21 | -------------------------------------------------------------------------------- /Codigos/Matemática/GCD/README.md: -------------------------------------------------------------------------------- 1 | # Máximo divisor comum 2 | 3 | Algoritmo Euclides para computar o Máximo Divisor Comum (MDC em português; GCD em inglês), e variações. 4 | 5 | *Read in [English](README.en.md)* 6 | 7 | # [Algoritmo de Euclides](gcd.cpp) 8 | 9 | Computa o Máximo Divisor Comum (MDC em português; GCD em inglês). 10 | 11 | - Complexidade de tempo: $\mathcal{O}(\log n)$ 12 | 13 | Mais demorado que usar a função do compilador C++ `__gcd(a,b)`. 14 | 15 | # [Algoritmo de Euclides Estendido](extended_gcd.cpp) 16 | 17 | Algoritmo extendido de euclides que computa o Máximo Divisor Comum e os valores x e y tal que a * x + b * y = gcd(a, b). 18 | 19 | - Complexidade de tempo: $\mathcal{O}(\log n)$ 20 | -------------------------------------------------------------------------------- /Codigos/Grafos/Centroids/Centroid/find_centroid.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | 3 | int sz[N]; 4 | vector adj[N]; 5 | 6 | void dfs_sz(int u, int p) { 7 | sz[u] = 1; 8 | for (int v : adj[u]) { 9 | if (v != p) { 10 | dfs_sz(v, u); 11 | sz[u] += sz[v]; 12 | } 13 | } 14 | } 15 | 16 | int centroid(int u, int p, int n) { 17 | for (int v : adj[u]) 18 | if (v != p && sz[v] > n / 2) return centroid(v, u, n); 19 | return u; 20 | } 21 | 22 | pair centroids(int u) { 23 | dfs_sz(u, u); 24 | int c = centroid(u, u, sz[u]); 25 | int c2 = -1; 26 | for (int v : adj[c]) 27 | if (sz[u] == sz[v] * 2) c2 = v; 28 | return {c, c2}; 29 | } -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Dijkstra/dijkstra.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | const ll INF = 1e18; 3 | 4 | int n; 5 | vector> adj[N]; 6 | 7 | vector dijkstra(int s) { 8 | vector dist(n, INF); 9 | using T = pair; 10 | priority_queue, greater<>> pq; 11 | dist[s] = 0; 12 | pq.emplace(dist[s], s); 13 | while (!pq.empty()) { 14 | auto [d, u] = pq.top(); 15 | pq.pop(); 16 | if (d != dist[u]) continue; 17 | for (auto [w, v] : adj[u]) { 18 | if (dist[v] > d + w) { 19 | dist[v] = d + w; 20 | pq.emplace(dist[v], v); 21 | } 22 | } 23 | } 24 | return dist; 25 | } 26 | -------------------------------------------------------------------------------- /Codigos/Grafos/Centroids/Centroid-Decomposition/README.md: -------------------------------------------------------------------------------- 1 | # [Centroid Decomposition](centroid_decomposition.cpp) 2 | 3 | Algoritmo que constrói a decomposição por centroides de uma árvore em $\mathcal{O}(N \log N)$. 4 | 5 | Basicamente, a decomposição consiste em, repetidamente: 6 | 7 | - Encontrar o centroide da árvore atual. 8 | - Remover o centroide e decompor as subárvores restantes. 9 | 10 | A decomposição vai gerar uma nova árvore (chamada comumente de "Centroid Tree") onde cada nodo é um centroide da árvore original e as arestas representam a relação de pai-filho entre os centroides. A árvore tem altura $\log N$. 11 | 12 | No código, `dis[u][j]` é a distância entre o nodo $u$ e seu $j$-ésimo ancestral na Centroid Tree. 13 | -------------------------------------------------------------------------------- /Codigos/Grafos/Kruskal/README.md: -------------------------------------------------------------------------------- 1 | # [Kruskal](kruskal.cpp) 2 | 3 | Algoritimo que utiliza DSU (Disjoint Set Union, descrita na seção de Estrutura de Dados) para encontrar a MST (Minimum Spanning Tree) de um grafo em $\mathcal{O}(E \log E)$. 4 | 5 | A Minimum Spanning Tree é a árvore geradora mínima de um grafo, ou seja, um conjunto de arestas que conecta todos os nodos do grafo com o menor custo possível. 6 | 7 | Propriedades importantes da MST: 8 | 9 | - É uma árvore! :O 10 | - Entre quaisquer dois nodos $u$ e $v$ do grafo, a MST minimiza a maior aresta no caminho de $u$ a $v$. 11 | 12 | Ideia do Kruskal: ordenar as arestas do grafo por peso e, para cada aresta, adicionar ela à MST se ela não forma um ciclo com as arestas já adicionadas. -------------------------------------------------------------------------------- /Codigos/String/Prefix-Function-KMP/KMP/kmp.cpp: -------------------------------------------------------------------------------- 1 | vector pi(string &s) { 2 | vector p(s.size()); 3 | for (int i = 1, j = 0; i < int(s.size()); i++) { 4 | while (j > 0 && s[i] != s[j]) j = p[j - 1]; 5 | if (s[i] == s[j]) j++; 6 | p[i] = j; 7 | } 8 | return p; 9 | } 10 | 11 | vector matching(string &s, string &t) { // s = texto, t = padrao 12 | vector p = pi(t), match; 13 | for (int i = 0, j = 0; i < (int)s.size(); i++) { 14 | while (j > 0 && s[i] != t[j]) j = p[j - 1]; 15 | if (s[i] == t[j]) j++; 16 | if (j == (int)t.size()) { 17 | match.push_back(i - j + 1); 18 | j = p[j - 1]; 19 | } 20 | } 21 | return match; 22 | } -------------------------------------------------------------------------------- /Codigos/Paradigmas/Divide-and-Conquer/README.md: -------------------------------------------------------------------------------- 1 | # [Divide and Conquer](dc.cpp) 2 | 3 | Otimização para DP de prefixo quando se pretende separar o vetor em $K$ subgrupos. 4 | 5 | É preciso fazer a função query(i, j) que computa o custo do subgrupo \[i, j\]. 6 | * Complexidade de tempo: $\mathcal{O}(n \cdot k \cdot \log(n) \cdot \mathcal{O}(\text{query}))$ 7 | 8 | # [Divide and Conquer com Query on demand](dc_query_ondemand.cpp) 9 | 10 | Usado para evitar queries pesadas ou o custo de pré-processamento. 11 | É preciso fazer as funções da estrutura **janela**, eles adicionam e removem itens um a um como uma janela flutuante. 12 | 13 | * Complexidade de tempo: $\mathcal{O}(n \cdot k \cdot \log(n) \cdot \mathcal{O}(\text{update da janela}))$ -------------------------------------------------------------------------------- /Codigos/Matemática/NTT/Taylor-Shift/taylor_shift.cpp: -------------------------------------------------------------------------------- 1 | template > 2 | vector shift(vector a, int k) { 3 | int n = (int)a.size(); 4 | vector fat(n, 1), ifat(n), shifting(n); 5 | for (int i = 1; i < n; i++) fat[i] = fat[i - 1] * i; 6 | ifat[n - 1] = T(1) / fat[n - 1]; 7 | for (int i = n - 1; i > 0; i--) ifat[i - 1] = ifat[i] * i; 8 | for (int i = 0; i < n; i++) a[i] *= fat[i]; 9 | T pk = 1; 10 | for (int i = 0; i < n; i++) { 11 | shifting[n - i - 1] = pk * ifat[i]; 12 | pk *= k; 13 | } 14 | auto ans = multiply(a, shifting); 15 | ans.erase(ans.begin(), ans.begin() + n - 1); 16 | for (int i = 0; i < n; i++) ans[i] *= ifat[i]; 17 | return ans; 18 | } -------------------------------------------------------------------------------- /Codigos/String/Z-function/z.cpp: -------------------------------------------------------------------------------- 1 | vector get_z(string &s) { 2 | int n = (int)s.size(); 3 | vector z(n); 4 | for (int i = 1, l = 0, r = 0; i < n; i++) { 5 | if (i <= r) z[i] = min(r - i + 1, z[i - l]); 6 | while (i + z[i] < n && s[i + z[i]] == s[z[i]]) z[i]++; 7 | if (i + z[i] - 1 > r) { 8 | r = i + z[i] - 1; 9 | l = i; 10 | } 11 | } 12 | return z; 13 | } 14 | 15 | vector matching(string &s, string &t) { // s = texto, t = padrao 16 | string k = t + "$" + s; 17 | vector z = get_z(k), match; 18 | int n = (int)t.size(); 19 | for (int i = n + 1; i < (int)z.size(); i++) 20 | if (z[i] == n) match.push_back(i - n - 1); 21 | return match; 22 | } -------------------------------------------------------------------------------- /LaTeX/preamble.tex: -------------------------------------------------------------------------------- 1 | \documentclass[9pt,a4paper,landscape]{article} 2 | 3 | \input{configs/packages} 4 | \input{configs/titlesec} 5 | \input{configs/listings} 6 | 7 | \setcounter{secnumdepth}{4} 8 | \setcounter{tocdepth}{3} 9 | 10 | \renewcommand{\contentsname}{Índice} 11 | 12 | \title{Almanaque de Códigos pra\\Maratona de Programação} 13 | \author{BRUTE UDESC} 14 | 15 | \makeatletter 16 | \renewcommand{\maketitle}{% 17 | \begin{titlepage}% 18 | \thispagestyle{empty}% 19 | \vspace*{\fill}% 20 | \begin{center}% 21 | {\Large\bfseries \@title\par}\vspace{1em}% 22 | {\large \@author\par}\vspace{1em}% 23 | {\normalsize \@date\par}% 24 | \end{center}% 25 | \vspace*{\fill}% 26 | \end{titlepage}% 27 | } 28 | \makeatother 29 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy-Esparsa/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree Lazy Esparsa](seg_tree_sparse_lazy.cpp) 2 | 3 | Segment Tree com Lazy Propagation e Esparsa. Está implementada com update de soma em range e atribuição em range, e query de soma em range. Construção em $\mathcal{O}(1)$ e operações de update e query em $\mathcal{O}(\log L)$, onde $L$ é o tamanho do intervalo. 4 | 5 | **Dica**: No construtor da Seg Tree, fazer `t.reserve(MAX); lazy.reserve(MAX); replace.reserve(MAX); Lc.reserve(MAX); Rc.reserve(MAX);` pode ajudar bastante no runtime, pois aloca espaço para os vetores e evita muitas realocações durante a execução. Nesse caso, `MAX` é geralmente $\mathcal{O}(Q \cdot \log L)$, onde $Q$ é o número de queries e $L$ é o tamanho do intervalo. -------------------------------------------------------------------------------- /Codigos/Grafos/Pontes/Pontes/find_bridges.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | int n, m, timer; 3 | vector adj[N]; 4 | int tin[N], low[N]; 5 | 6 | void dfs_bridge(int u, int p = -1) { 7 | low[u] = tin[u] = ++timer; 8 | for (int v : adj[u]) { 9 | if (tin[v] != 0 && v != p) { 10 | low[u] = min(low[u], tin[v]); 11 | } else if (v != p) { 12 | dfs_bridge(v, u); 13 | low[u] = min(low[u], low[v]); 14 | } 15 | } 16 | if (p != -1 && low[u] == tin[u]) { 17 | // edge (p, u) eh ponte 18 | } 19 | } 20 | 21 | void find_bridges() { 22 | timer = 0; 23 | for (int i = 0; i < n; i++) tin[i] = low[i] = 0; 24 | for (int i = 0; i < n; i++) 25 | if (tin[i] == 0) dfs_bridge(i); 26 | } -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Divisores/Divisores-Rápido/README.md: -------------------------------------------------------------------------------- 1 | # [Divisores Rápido](get_divs.cpp) 2 | 3 | Algoritmo que obtém todos os divisores de um número em $\mathcal{O}(\text{d(X)})$, onde $d(X)$ é a quantidade de divisores do número. Geralmente, para um número $X$, dizemos que a quantidade de divisores é $\mathcal{O}(\sqrt[3]{X})$. 4 | 5 | De fato, para números até $10^{88}$, é verdade que $d(n) < 3.6 \cdot \sqrt[3]{n}$. 6 | 7 | **Obs**: Usar algum código de fatoração presente nesse almanaque para obter os fatores do número. 8 | - `Crivo/Crivo-Linear/linear_sieve.cpp` tem uma função de fatoração em $\mathcal{O}(\log X)$. 9 | - `Fatores/Fatoração-Rápida/fast_factorize.cpp` tem uma função de fatoração em tempo médio $\mathcal{O}(\log X)$ que aceita até inteiros de 64 bits. -------------------------------------------------------------------------------- /LaTeX/configs/packages.tex: -------------------------------------------------------------------------------- 1 | \usepackage[T1]{fontenc} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[brazil]{babel} 4 | \usepackage{lmodern} 5 | \usepackage{amsmath,amssymb} 6 | \usepackage[final]{microtype} 7 | \usepackage[paper=a4paper,margin=9mm]{geometry} 8 | \usepackage{comment} 9 | \usepackage{datetime} 10 | \usepackage[all]{xy} 11 | \usepackage{graphicx} 12 | \usepackage{multicol} 13 | \usepackage{enumitem} 14 | \usepackage{xcolor} 15 | \usepackage{colortbl} 16 | \usepackage{hyperref} 17 | 18 | \setlength{\parindent}{0pt} 19 | \setlength{\parskip}{0.25\baselineskip} 20 | \linespread{0.96} 21 | 22 | \setlist{nosep,leftmargin=*} 23 | 24 | \setlength{\columnsep}{18pt} 25 | \setlength{\columnseprule}{0.2pt} 26 | \def\columnseprulecolor{\color{black}} 27 | \raggedcolumns 28 | -------------------------------------------------------------------------------- /Codigos/Matemática/Continued-Fractions/README.md: -------------------------------------------------------------------------------- 1 | # [Frações Contínuas](continued_fractions.cpp) 2 | Inspirado pelo artigo no CP Algorithms: https://cp-algorithms.com/algebra/continued-fractions.html 3 | 4 | Computa fração contínua a partir de fração racional e vice-versa. 5 | `lca(u, v)` computa o lca das frações `u` e `v` na Stern-Brocott Tree 6 | 7 | Tamanho da fração contínua e complexidade para computá-la a partir da fração racional A/B: $\mathcal{O}(\log (A + B))$. 8 | Portanto, lca e outros métodos têm mesma complexidade. 9 | 10 | Testado apenas em: https://atcoder.jp/contests/abc408/tasks/abc408_g 11 | 12 | IMPORTANTE: Cuidado com "inf" quando usando "plus_minus_eps" - chamar "convergents" para uma fração contínua 13 | com "inf" no final restulta em overflow. 14 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Fatores/Fatoração-Rápida/README.md: -------------------------------------------------------------------------------- 1 | # [Fatoração Rápida](fast_factorize.cpp) 2 | 3 | Algoritmo que combina o Crivo de Eratóstenes Linear, Miller-Rabin e Pollard Rho para fatorar um número $X$ em tempo médio $\mathcal{O}(\log X)$, no pior caso pode ser $\mathcal{O}(\sqrt[4]{X} \cdot \log X)$, mas na prática é seguro considerar $\mathcal{O}(\log X)$. 4 | 5 | Esse código deve ser usado quando se deseja fatorar números $> 10^7$, por exemplo. Caso os números não sejam tão grandes assim, usar apenas o Crivo de Eratóstenes Linear sozinho é mais prático. 6 | 7 | **Obs**: Usa três outros códigos desse Almanaque da seção Matemática: 8 | - `Crivo/Crivo-Linear/linear_sieve.cpp` 9 | - `Teste-Primalidade/Miller-Rabin/miller_rabin.cpp`- 10 | - `Pollard-Rho/pollard_rho.cpp`. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Operation-Queue/op_queue.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct op_queue { 3 | op_stack in, out; 4 | void push(T x) { in.push(x); } 5 | void pop() { 6 | if (out.empty()) { 7 | while (!in.empty()) { 8 | out.push(in.top()); 9 | in.pop(); 10 | } 11 | } 12 | out.pop(); 13 | } 14 | T get() { 15 | if (out.empty()) return in.get(); 16 | if (in.empty()) return out.get(); 17 | return OP(in.get(), out.get()); 18 | } 19 | T front() { 20 | if (out.empty()) return in.bottom(); 21 | return out.top(); 22 | } 23 | T back() { 24 | if (in.empty()) return out.bottom(); 25 | return in.top(); 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/AND-Convolution/and_convolution.cpp: -------------------------------------------------------------------------------- 1 | vector and_convolution(vector A, vector B) { 2 | int n = (int)max(A.size(), B.size()); 3 | int N = 0; 4 | while ((1 << N) < n) N++; 5 | A.resize(1 << N); 6 | B.resize(1 << N); 7 | vector C(1 << N); 8 | for (int j = 0; j < N; j++) { 9 | for (int i = (1 << N) - 1; i >= 0; i--) { 10 | if (~i >> j & 1) { 11 | A[i] += A[i | (1 << j)]; 12 | B[i] += B[i | (1 << j)]; 13 | } 14 | } 15 | } 16 | for (int i = 0; i < 1 << N; i++) C[i] = A[i] * B[i]; 17 | for (int j = 0; j < N; j++) { 18 | for (int i = 0; i < 1 << N; i++) 19 | if (~i >> j & 1) C[i] -= C[i | (1 << j)]; 20 | } 21 | return C; 22 | } 23 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/OR-Convolution/or_convolution.cpp: -------------------------------------------------------------------------------- 1 | vector or_convolution(vector A, vector B) { 2 | int n = (int)max(A.size(), B.size()); 3 | int N = 0; 4 | while ((1 << N) < n) N++; 5 | A.resize(1 << N); 6 | B.resize(1 << N); 7 | vector C(1 << N); 8 | for (int j = 0; j < N; j++) { 9 | for (int i = 0; i < 1 << N; i++) { 10 | if (i >> j & 1) { 11 | A[i] += A[i ^ (1 << j)]; 12 | B[i] += B[i ^ (1 << j)]; 13 | } 14 | } 15 | } 16 | for (int i = 0; i < 1 << N; i++) C[i] = A[i] * B[i]; 17 | for (int j = N - 1; j >= 0; j--) { 18 | for (int i = (1 << N) - 1; i >= 0; i--) 19 | if (i >> j & 1) C[i] -= C[i ^ (1 << j)]; 20 | } 21 | return C; 22 | } 23 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU-Rollback/README.md: -------------------------------------------------------------------------------- 1 | # [DSU com Rollback](rollback_dsu.cpp) 2 | 3 | DSU que desfaz as últimas operações. O método `checkpoint` salva o estado atual da estrutura, e o método `rollback` desfaz as últimas operações até o último checkpoint. As operações de unir dois conjuntos e verificar em qual conjunto um elemento está são $\mathcal{O}(\log N)$, o rollback é $\mathcal{O}(K)$, onde $K$ é o número de alterações a serem desfeitas e o `checkpoint` é $\mathcal{O}(1)$. Importante notar que o rollback não altera a complexidade de uma solução, uma vez que $\sum K = \mathcal{O}(Q)$, onde $Q$ é o número de operações realizadas. 4 | 5 | Para alterar uma variável da DSU durante o unite, deve-se usar o método `change`, pois ele coloca as alterações numa stack para depois poder revertê-las. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree](seg_tree.cpp) 2 | 3 | Implementação padrão de Segment Tree, suporta operações de consulta em intervalo e update pontual. Está implementada para soma, mas pode ser facilmente modificada para outras operações. A construção é $\mathcal{O}(n)$ e as operações de consulta e update são $\mathcal{O}(\log n)$. 4 | 5 | **Dica**: A Seg Tree usa $4 \cdot n$ de memória pois cada nodo $p$ tem seus filhos $2 \cdot p$ (filho esquerdo) e $2 \cdot p + 1$ (filho direito). Há uma forma de indexar os nodos que usa $2 \cdot n$ de memória. Dado um nodo $p$ que representa o intervalo $[l, r]$, seu filho esquerdo é $p+1$ (e representa o intervalo $[l, mid]$) e seu filho direito é $p+2 \cdot (mid-l+1)$ (e representa o intervalo $[mid+1, r]$), onde $mid = (l+r)/2$. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Eliminação-Gaussiana/Gauss/README.md: -------------------------------------------------------------------------------- 1 | # [Eliminação Gaussiana](gauss.cpp) 2 | 3 | Método de eliminação gaussiana para resolução de sistemas lineares com coeficientes reais, a complexidade é $\mathcal{O}(n^3)$. 4 | 5 | A função `gauss` recebe como parâmetros: 6 | - `vector> a`: uma matriz $N \times (M + 1)$, onde $N$ é o número de equações e $M$ é o número de variáveis, a última coluna de `a` deve conter o resultado das equações. 7 | - `vector &ans`: um vetor de tamanho $M$, que será preenchido com a solução do sistema, caso exista. 8 | 9 | A função retorna: 10 | - `0`: se o sistema não tem solução. 11 | - `1`: se o sistema tem uma única solução. 12 | - `INF`: se o sistema tem infinitas soluções. Nesse caso, as variáveis em que `where[i] == -1` são as variáveis livres. 13 | -------------------------------------------------------------------------------- /Codigos/Matemática/Teorema-do-Resto-Chinês/crt.cpp: -------------------------------------------------------------------------------- 1 | ll extended_gcd(ll a, ll b, ll &x, ll &y) { 2 | if (b == 0) { 3 | x = 1; 4 | y = 0; 5 | return a; 6 | } else { 7 | ll g = extended_gcd(b, a % b, y, x); 8 | y -= a / b * x; 9 | return g; 10 | } 11 | } 12 | 13 | ll crt(vector rem, vector mod) { 14 | int n = rem.size(); 15 | if (n == 0) return 0; 16 | __int128 ans = rem[0], m = mod[0]; 17 | for (int i = 1; i < n; i++) { 18 | ll x, y; 19 | ll g = extended_gcd(mod[i], m, x, y); 20 | if ((ans - rem[i]) % g != 0) return -1; 21 | ans = ans + (__int128)1 * (rem[i] - ans) * (m / g) * y; 22 | m = (__int128)(mod[i] / g) * (m / g) * g; 23 | ans = (ans % m + m) % m; 24 | } 25 | return ans; 26 | } 27 | -------------------------------------------------------------------------------- /Codigos/String/Prefix-Function-KMP/Automato-KMP/aut_kmp.cpp: -------------------------------------------------------------------------------- 1 | struct AutKMP { 2 | vector> nxt; 3 | void setString(string s) { 4 | s += '#'; 5 | nxt.assign(s.size(), vector(26)); 6 | vector p = pi(s); 7 | for (int c = 0; c < 26; c++) nxt[0][c] = ('a' + c == s[0]); 8 | for (int i = 1; i < int(s.size()); i++) 9 | for (int c = 0; c < 26; c++) 10 | nxt[i][c] = ('a' + c == s[i]) ? i + 1 : nxt[p[i - 1]][c]; 11 | } 12 | vector matching(string &s, string &t) { 13 | vector match; 14 | for (int i = 0, j = 0; i < int(s.size()); i++) { 15 | j = nxt[j][s[i] - 'a']; 16 | if (j == int(t.size())) match.push_back(i - j + 1); 17 | } 18 | return match; 19 | } 20 | } aut; 21 | -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: clang-format Checker 2 | 3 | on: 4 | workflow_dispatch: {} 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | # A verificação no 'push' pra 'main' foi desabilitada por ser redundante. 10 | # Já que push direto na main está bloqueado e tudo tem que passar por um PR que já vai rodar essa action. 11 | # push: 12 | # branches: 13 | # - main 14 | 15 | jobs: 16 | formatting-check: 17 | name: Formatting Check 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v3 21 | 22 | - name: Run clang-format style check for C++ programs 23 | uses: jidicula/clang-format-action@v4.15.0 24 | with: 25 | clang-format-version: '20' 26 | check-path: 'Codigos' 27 | fallback-style: 'LLVM' 28 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Divisores/Divisores-Rápido/get_divs.cpp: -------------------------------------------------------------------------------- 1 | vector get_divs(ll n) { 2 | vector divs; 3 | auto f = factorize(n); // qualquer código que fatore n 4 | sort(f.begin(), f.end()); 5 | vector> v; 6 | for (auto x : f) 7 | if (v.empty() || v.back().first != x) v.emplace_back(x, 1); 8 | else v.back().second += 1; 9 | auto dfs = [&](auto &&self, int i, ll cur) -> void { 10 | if (i == (int)v.size()) { 11 | divs.push_back(cur); 12 | return; 13 | } 14 | ll p = 1; 15 | for (int j = 0; j <= v[i].second; j++) { 16 | self(self, i + 1, cur * p); 17 | p *= v[i].first; 18 | } 19 | }; 20 | dfs(dfs, 0, 1); 21 | sort(divs.begin(), divs.end()); 22 | return divs; 23 | } 24 | -------------------------------------------------------------------------------- /Codigos/String/EertreE/README.md: -------------------------------------------------------------------------------- 1 | # [EertreE](eertree.cpp) 2 | 3 | Constrói a Palindromic Tree de uma string $S$ em $\mathcal{O}(|S|)$. Todo nodo da árvore representa exatamente uma substring palindrômica de $S$. 4 | 5 | - `len[u]` representa o tamanho do palíndromo representado pelo nodo `u`. 6 | - `lnk[u]` é o nodo que representa o maior sufixo palindrômico do nodo `u`. 7 | - `cnt[u]` é a frequência da substring representada pelo nodo `u`. 8 | - `first[u]` representa a primeira ocorrência da substring representada pelo nodo `u`, note que `first[u]` guarda o índice do último caractere dessa substring. 9 | - `number_of_palindromes()` retorna a quantidade de substrings palindrômicas de $S$, lembre-se de chamar a função `build_cnt()` antes dessa. 10 | - `number_of_distinct_palindromes()` retorna a quantidade de substrings palindrômicas distintas. -------------------------------------------------------------------------------- /Codigos/Paradigmas/Busca-Ternaria/README.md: -------------------------------------------------------------------------------- 1 | # [Busca Ternária](busca_ternaria.cpp) 2 | 3 | Encontra um ponto ótimo em uma função que pode ser separada em duas funções estritamente monotônicas (por exemplo, parábolas). 4 | 5 | - Complexidade de tempo: $\mathcal{O}(\log(N) \cdot \mathcal{O}(\text{eval}))$, onde $N$ é o tamanho do espaço de busca e ($\mathcal{O}(\text{eval})$) é o custo de avaliação da função. 6 | 7 | # [Busca Ternária em Espaço Discreto](busca_ternaria_discreta.cpp) 8 | 9 | Encontra um ponto ótimo em uma função que pode ser separada em duas funções estritamente monotônicas (por exemplo, parábolas). 10 | Versão para espaços discretos. 11 | 12 | - Complexidade de tempo: $\mathcal{O}(\log(N) \cdot \mathcal{O}(\text{eval}))$, onde $N$ é o tamanho do espaço de busca e ($\mathcal{O}(\text{eval})$) é o custo de avaliação da função. 13 | -------------------------------------------------------------------------------- /Codigos/String/Patricia-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [Patricia Tree (ou Patricia Trie)](patricia_tree.cpp) 2 | 3 | Estrutura de dados que armazena strings e permite consultas por prefixo, muito similar a uma Trie. Todas as operações são $\mathcal{O}(|s|)$. 4 | 5 | **Obs**: Não aceita elementos repetidos. 6 | 7 | Implementação PB-DS, extremamente curta e confusa: 8 | 9 | Exemplo de uso: 10 | 11 | ```cpp 12 | patricia_tree pat; 13 | pat.insert("exemplo"); 14 | pat.erase("exemplo"); 15 | pat.find("exemplo") != pat.end(); // verifica existência 16 | auto match = pat.prefix_range("ex"); // pega palavras que começam com "ex" 17 | for (auto it = match.first; it != match.second; ++it); // percorre match 18 | pat.lower_bound("ex"); // menor elemento lexicográfico maior ou igual a "ex" 19 | pat.upper_bound("ex"); // menor elemento lexicográfico maior que "ex" 20 | ``` -------------------------------------------------------------------------------- /Codigos/Grafos/Virtual-Tree/virtual_tree.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | #warning nao esquece de copiar o codigo de LCA 3 | vector vir_tree[N]; 4 | vector vir_nodes; 5 | 6 | void build_virtual_tree(vector S) { 7 | sort(S.begin(), S.end(), [&](int i, int j) { return bl::tin[i] < bl::tin[j]; }); 8 | for (int i = 1; i < (int)S.size(); i++) S.emplace_back(bl::lca(S[i - 1], S[i])); 9 | sort(S.begin(), S.end(), [&](int i, int j) { return bl::tin[i] < bl::tin[j]; }); 10 | S.erase(unique(S.begin(), S.end()), S.end()); 11 | vir_nodes = S; 12 | for (auto u : S) vir_tree[u].clear(); 13 | vector stk; 14 | for (auto u : S) { 15 | while (stk.size() && !bl::ancestor(stk.back(), u)) stk.pop_back(); 16 | if (stk.size()) vir_tree[stk.back()].emplace_back(u); 17 | stk.emplace_back(u); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Implicit-Treap/README.md: -------------------------------------------------------------------------------- 1 | # [Implicit Treap](implicit_treap.cpp) 2 | 3 | Simula um array com as seguintes operações em $\mathcal{O}(\log N)$: 4 | 5 | - Inserir um elemento $X$ na posição $i$ (todos os elementos em posições maiores que $i$ serão "empurrados" para a direita). 6 | - Remover o elemento na posição $i$ (todos os elementos em posições maiores que $i$ serão "puxados" para a esquerda). 7 | - Query em intervalo $[L, R]$ de alguma operação. Pode ser soma, máximo, mínimo, `gcd`, etc. 8 | - Adição em intervalo $[L, R]$ (sua operação deve suportar propagação lazy). 9 | - Reverter um intervalo $[L, R]$, ou seja, $a[L], a[L + 1], \cdots, a[R] \rightarrow a[R], a[R - 1], \cdots, a[L]$. 10 | 11 | **Obs**: Inserir em uma posição $<0$ vai inserir na posição $0$, assim como inserir em uma posição $>\text{Tamanho da Treap}$ vai inserir no final dela. 12 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Persistente/README.md: -------------------------------------------------------------------------------- 1 | # [Seg Tree Persistente](seg_tree_persistent.cpp) 2 | 3 | Uma Seg Tree Esparsa, só que com persistência, ou seja, pode voltar para qualquer estado anterior da árvore, antes de qualquer modificação. 4 | 5 | Os métodos `query` e `update` agora recebem um parâmetro a mais, que é a root (versão da árvore) que se deja modificar. Todos os métodos continuam $\mathcal{O}(\log n)$. 6 | 7 | O vetor `roots` guarda na posição `i` a root da árvore após o `i`-ésimo update. 8 | 9 | **Dica**: No construtor da Seg Tree, fazer `t.reserve(MAX); Lc.reserve(MAX); Rc.reserve(MAX); roots.reserve(Q);` pode ajudar bastante no runtime, pois aloca espaço para os vetores e evita muitas realocações durante a execução. Nesse caso, `MAX` é geralmente $\mathcal{O}(Q \cdot \log L)$, onde $Q$ é o número de queries e $L$ é o tamanho do intervalo. -------------------------------------------------------------------------------- /Codigos/Extra/Debug/debug.cpp: -------------------------------------------------------------------------------- 1 | template 2 | ostream &operator<<(ostream &os, const pair &p) { // opcional 3 | os << "(" << p.first << ", " << p.second << ")"; 4 | return os; 5 | } 6 | template 7 | ostream &operator<<(ostream &os, const vector &v) { // opcional 8 | os << "{"; 9 | int n = (int)v.size(); 10 | for (int i = 0; i < n; i++) { 11 | os << v[i]; 12 | if (i < n - 1) os << ", "; 13 | } 14 | os << "}"; 15 | return os; 16 | } 17 | 18 | void _print() { } 19 | template 20 | void _print(T a, U... b) { 21 | if (sizeof...(b)) { 22 | cerr << a << ", "; 23 | _print(b...); 24 | } else cerr << a; 25 | } 26 | #ifdef BRUTE 27 | #define debug(x...) cerr << "[" << #x << "] = [", _print(x), cerr << "]" << endl 28 | #else 29 | #define debug(...) 30 | #endif -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Sparse-Table/Sparse-Table/sparse_table.cpp: -------------------------------------------------------------------------------- 1 | struct SparseTable { 2 | int n, LG; 3 | vector> st; 4 | ll merge(ll a, ll b) { return min(a, b); } 5 | const ll neutral = 1e18; 6 | void build(const vector &v) { 7 | n = (int)v.size(); 8 | LG = 32 - __builtin_clz(n); 9 | st = vector>(LG, vector(n)); 10 | for (int i = 0; i < n; i++) st[0][i] = v[i]; 11 | for (int i = 0; i < LG - 1; i++) 12 | for (int j = 0; j + (1 << i) < n; j++) 13 | st[i + 1][j] = merge(st[i][j], st[i][j + (1 << i)]); 14 | } 15 | void build(ll *bg, ll *en) { build(vector(bg, en)); } 16 | ll query(int l, int r) { 17 | if (l > r) return neutral; 18 | int i = 31 - __builtin_clz(r - l + 1); 19 | return merge(st[i][l], st[i][r - (1 << i) + 1]); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /Codigos/Grafos/Binary-Lifting/Binary-Lifting-Query/README.md: -------------------------------------------------------------------------------- 1 | # [Binary Lifting Query](binary_lifting_query_nodo.cpp) 2 | 3 | Binary Lifting em que, além de queries de ancestrais, podemos fazer queries em caminhos. Seja $f(u, v)$ uma função que retorna algo sobre o caminho entre $u$ e $v$, como a soma dos valores dos nodos ou máximo valor do caminho, `st[u][i]` é o valor de $f(par[u], up[u][i])$, em que `up[u][i]` é o $2 ^ i$-ésimo ancestral de `u` e `par[u]` é o pai de `u`. A função $f$ deve ser associativa e comutativa. 4 | 5 | A construção é $\mathcal{O}(n \log n)$, e é possível consultar em $\mathcal{O}(\log n)$ pelo valor de $f(u, v)$, em que $u$ e $v$ são nodos do grafo, através do método `query`. Também computa LCA e $k$-ésimo ancestral em $\mathcal{O}(\log n)$. 6 | 7 | **Obs**: os valores precisam estar nos **nodos** e não nas arestas, para valores nas arestas verificar o `Binary Lifting Query Aresta`. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree Lazy](seg_tree_lazy.cpp) 2 | 3 | Lazy Propagation é uma técnica para updatar a Segment Tree que te permite fazer updates em intervalos, não necessariamente pontuais. Esta implementação responde consultas de soma em intervalo e updates de soma ou atribuição em intervalo, veja o método `update`. 4 | 5 | A construção é $\mathcal{O}(n)$ e as operações de consulta e update são $\mathcal{O}(\log n)$. 6 | 7 | **Dica**: A Seg Tree usa $4 \cdot n$ de memória pois cada nodo $p$ tem seus filhos $2 \cdot p$ (filho esquerdo) e $2 \cdot p + 1$ (filho direito). Há uma forma de indexar os nodos que usa $2 \cdot n$ de memória. Dado um nodo $p$ que representa o intervalo $[l, r]$, seu filho esquerdo é $p+1$ (e representa o intervalo $[l, mid]$) e seu filho direito é $p+2 \cdot (mid-l+1)$ (e representa o intervalo $[mid+1, r]$), onde $mid = (l+r)/2$. -------------------------------------------------------------------------------- /Codigos/Grafos/Caminho-Euleriano/Caminho-Euleriano-Nao-Direcionado/README.md: -------------------------------------------------------------------------------- 1 | # [Caminho Euleriano (Grafo Não Direcionado)](undirected_eulerian_path.cpp) 2 | 3 | Algoritmo para encontrar um caminho euleriano em um grafo não direcionado em $\mathcal{O}(V + E)$. O algoritmo também encontrará um ciclo euleriano se o mesmo existir. Se nem um ciclo nem um caminho euleriano existir, o algoritmo retornará um vetor vazio. 4 | 5 | **Definição**: Um caminho euleriano é um caminho que passa por todas as arestas de um grafo exatamente uma vez. Um ciclo euleriano é um caminho euleriano que começa e termina no mesmo vértice. A condição de existência de um ciclo euleriano (em um grafo não direcionado) é que todos os vértices do grafo possuam grau par. A condição de existência de um caminho euleriano (em um grafo não direcionado) é que o grafo possua exatamente dois vértices com grau ímpar, um deles será o vértice de início e o outro o vértice de término. 6 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Dirichlet-Convolution/Dirichlet-Convolution-Prefix/dirichlet_convolution_prefix.cpp: -------------------------------------------------------------------------------- 1 | struct DirichletConvolutionPrefix { 2 | ll N; 3 | int T; 4 | vector ans; 5 | 6 | DirichletConvolutionPrefix(ll n, int t) : N(n), T(t) { ans.assign(n / T + 1, 0); } 7 | 8 | vector solve(auto &&f, auto &&F, auto &&g, auto &&G) { 9 | if (N == 1) return vector(2, 1); 10 | ans.assign(N / T + 1, 0); 11 | for (ll i = 1; i <= N / T; i++) { 12 | ll now = N / i; 13 | mint f_sum = 0, g_sum = 0; 14 | for (int j = 1; (ll)j * j <= now; j++) { 15 | f_sum += f(j); 16 | g_sum += g(j); 17 | 18 | ans[i] += G(i * j) * f(j); 19 | ans[i] += F(i * j) * g(j); 20 | } 21 | ans[i] -= f_sum * g_sum; 22 | } 23 | return ans; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /Codigos/Extra/Random/README.md: -------------------------------------------------------------------------------- 1 | # [Random em C++](rand.cpp) 2 | 3 | É possível usar a função `rand()` para gerar números aleatórios em `C++`. 4 | Útil para gerar casos aleatórios em stress test, porém não é recomendado para usar em soluções. 5 | `rand()` gera números entre `0` e `RAND_MAX` (que é pelo menos `32767`), mas costuma ser `2147483647` (depende do sistema/arquitetura). 6 | Para usar o `rand()`, recomenda-se no mínimo chamar a função `srand(time(0))` no início da `main()` para inicializar a seed do gerador de números aleatórios. 7 | 8 | Para usar números aleatórios em soluções, recomenda-se o uso do `mt19937` que está no código abaixo. 9 | A função `rng()` gera números entre `0` e `UINT_MAX` (que é `4294967295`). 10 | Para gerar números aleatórios de 64 bits, usar `mt19937_64` como tipo do `rng`. 11 | Recomenda-se o uso da função `uniform(l, r)` para gerar números aleatórios no intervalo fechado $[l, r]$ usando o `mt19937`. 12 | -------------------------------------------------------------------------------- /Codigos/Grafos/Fluxo/README.md: -------------------------------------------------------------------------------- 1 | # Fluxo 2 | 3 | Conjunto de algoritmos para calcular o fluxo máximo em redes de fluxo. 4 | 5 | ## Dinic 6 | 7 | Adequado para grafos densos ou bipartidos. O grafo é armazenado internamente e as arestas devem ser adicionadas com `add_edge`. 8 | 9 | - Complexidade de tempo: $\mathcal{O}(V^2 \cdot E)$; em grafos bipartidos, $\mathcal{O}(\sqrt{V} \cdot E)$. 10 | 11 | A chamada `max_flow` altera o grafo adicionando o maior fluxo possível e retorna o valor desse fluxo máximo. 12 | 13 | O corte mínimo de um grafo é equivalente ao fluxo máximo. Após `max_flow`, use `min_cut` para obter as arestas que compõem o corte mínimo. 14 | 15 | ## Edmonds-Karp 16 | 17 | Indicado para grafos com poucas arestas. 18 | 19 | - Complexidade de tempo: $\mathcal{O}(V \cdot E^2)$. 20 | 21 | ## Min Cost Max Flow 22 | 23 | Calcula o fluxo máximo com custo mínimo. 24 | 25 | - Complexidade de tempo: $\mathcal{O}(V^2 \cdot E^2)$. 26 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/DP-de-Permutacao/tsp_dp.cpp: -------------------------------------------------------------------------------- 1 | const int lim = 17; // setar para o maximo de itens 2 | long double dist[lim][lim]; // eh preciso dar as 3 | // distancias de n para n 4 | long double dp[lim][1 << lim]; 5 | 6 | int limMask = (1 << lim) - 1; // 2**(maximo de itens) - 1 7 | long double solve(int atual, int mask, int n) { 8 | if (dp[atual][mask] != 0) return dp[atual][mask]; 9 | if (mask == (1 << n) - 1) { 10 | return dp[atual][mask] = 0; // o que fazer quando 11 | // chega no final 12 | } 13 | 14 | long double res = 1e13; // pode ser maior se precisar 15 | for (int i = 0; i < n; i++) { 16 | if (!(mask & (1 << i))) { 17 | long double aux = solve(i, mask | (1 << i), n); 18 | if (mask) aux += dist[atual][i]; 19 | res = min(res, aux); 20 | } 21 | } 22 | return dp[atual][mask] = res; 23 | } 24 | -------------------------------------------------------------------------------- /Codigos/Grafos/Pontos-de-Articulacao/articulation_points.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | int n, m, timer; 3 | vector adj[N]; 4 | int tin[N], low[N]; 5 | 6 | void dfs(int u, int p = -1) { 7 | low[u] = tin[u] = ++timer; 8 | int child = 0; 9 | for (int v : adj[u]) { 10 | if (tin[v] != 0 && v != p) { 11 | low[u] = min(low[u], tin[v]); 12 | } else if (v != p) { 13 | dfs(v, u); 14 | low[u] = min(low[u], low[v]); 15 | if (p != -1 && low[v] >= tin[u]) { 16 | // vertice u eh um ponto de articulacao 17 | } 18 | child++; 19 | } 20 | } 21 | if (p == -1 && child > 1) { 22 | // vertice u eh um ponto de articulacao 23 | } 24 | } 25 | 26 | void find_articulation_points() { 27 | timer = 0; 28 | for (int i = 0; i < n; i++) tin[i] = low[i] = 0; 29 | for (int i = 0; i < n; i++) 30 | if (tin[i] == 0) dfs(i); 31 | } 32 | -------------------------------------------------------------------------------- /LaTeX/chapters/01-cpp/compilador.tex: -------------------------------------------------------------------------------- 1 | \subsection{Compilador} 2 | 3 | Para compilar um arquivo \texttt{.cpp} com o compilador \texttt{g++}, usar o comando: 4 | 5 | \begin{lstlisting}[language=bash] 6 | g++ -std=c++20 -O2 arquivo.cpp 7 | \end{lstlisting} 8 | 9 | \textbf{Obs:} a flag \texttt{-std=c++20} é para usar a versão 20 do C++, os códigos desse Almanaque são testados com essa versão. 10 | 11 | Algumas flags úteis para o \texttt{g++} são: 12 | 13 | \begin{itemize} 14 | \item \texttt{-O2}: Otimizações de compilação 15 | \item \texttt{-Wall}: Mostra todos os warnings 16 | \item \texttt{-Wextra}: Mostra mais warnings 17 | \item \texttt{-Wconversion}: Mostra warnings para conversões implícitas 18 | \item \texttt{-fsanitize=address}: Habilita o AddressSanitizer 19 | \item \texttt{-fsanitize=undefined}: Habilita o UndefinedBehaviorSanitizer 20 | \end{itemize} 21 | 22 | Todas essas flags já estão presente no script `run` da seção Extra. 23 | -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Crivo/Crivo-Linear/linear_sieve.cpp: -------------------------------------------------------------------------------- 1 | namespace Sieve { 2 | const int P = 5e6 + 1; 3 | vector is_prime(P, true); 4 | int lpf[P], primes[P], cnt = 0; 5 | void build() { 6 | is_prime[0] = is_prime[1] = 0; 7 | for (int i = 2; i < P; i++) { 8 | if (is_prime[i]) { 9 | lpf[i] = i; 10 | primes[cnt++] = i; 11 | } 12 | for (int j = 0; j < cnt && i * primes[j] < P; j++) { 13 | is_prime[i * primes[j]] = 0; 14 | lpf[i * primes[j]] = primes[j]; 15 | if (i % primes[j] == 0) break; 16 | } 17 | } 18 | } 19 | vector factorize(int n) { 20 | #warning lembra de chamar o build() antes de fatorar! 21 | vector f; 22 | while (n > 1) { 23 | f.push_back(lpf[n]); 24 | n /= lpf[n]; 25 | } 26 | return f; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Codigos/String/Hashing/Hashing-Dinâmico/README.md: -------------------------------------------------------------------------------- 1 | # [Hashing Dinâmico](dynamic_hashing.cpp) 2 | 3 | Hashing polinomial para testar igualdade de strings (ou de vetores). Requer precomputar as potências de um primo, como indicado na função `precalc`. A implementação está com dois MODS e usa a primitiva `Mint`, a escolha de usar apenas um MOD ou não usar o `Mint` vai da sua preferência ou necessidade, se não usar o `Mint`, trate adequadamente as operações com aritmética modular. 4 | Essa implementação suporta updates pontuais, utilizando-se de uma `Fenwick Tree` para isso. A construção é $\mathcal{O}(n)$, consultas e updates são $\mathcal{O}(\log n)$. 5 | 6 | **Obs**: lembrar de chamar a função `precalc`! 7 | 8 | Exemplo de uso: 9 | 10 | ```cpp 11 | string s = "abacabab"; 12 | DynamicHashing a(s); 13 | cout << (a(0, 1) == a(2, 3)) << endl; // 0 14 | cout << (a(0, 1) == a(4, 5)) << endl; // 1 15 | a.update(0, 'c'); 16 | cout << (a(0, 1) == a(4, 5)) << endl; // 0 17 | ``` 18 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/SPFA/spfa.cpp: -------------------------------------------------------------------------------- 1 | const int N = 1e4 + 5; 2 | const ll INF = 1e18; 3 | 4 | int n; 5 | vector> adj[N]; 6 | 7 | vector spfa(int s) { 8 | vector dist(n, INF); 9 | vector cnt(n, 0); 10 | vector inq(n, false); 11 | queue q; 12 | q.push(s); 13 | inq[s] = true; 14 | dist[s] = 0; 15 | while (!q.empty()) { 16 | int u = q.front(); 17 | q.pop(); 18 | inq[u] = false; 19 | for (auto [w, v] : adj[u]) { 20 | ll newd = (dist[u] == -INF ? -INF : max(w + dist[u], -INF)); 21 | if (newd < dist[v]) { 22 | dist[v] = newd; 23 | if (!inq[v]) { 24 | q.push(v); 25 | inq[v] = true; 26 | cnt[v]++; 27 | if (cnt[v] > n) dist[v] = -INF; // negative cycle 28 | } 29 | } 30 | } 31 | } 32 | return dist; 33 | } 34 | -------------------------------------------------------------------------------- /Codigos/String/Suffix-Array/suffix_array_busca.cpp: -------------------------------------------------------------------------------- 1 | pair busca(string &t, int i, pair &range) { 2 | int esq = range.first, dir = range.second, L = -1, R = -1; 3 | while (esq <= dir) { 4 | int mid = (esq + dir) / 2; 5 | if (s[sa[mid] + i] == t[i]) L = mid; 6 | if (s[sa[mid] + i] < t[i]) esq = mid + 1; 7 | else dir = mid - 1; 8 | } 9 | esq = range.first, dir = range.second; 10 | while (esq <= dir) { 11 | int mid = (esq + dir) / 2; 12 | if (s[sa[mid] + i] == t[i]) R = mid; 13 | if (s[sa[mid] + i] <= t[i]) esq = mid + 1; 14 | else dir = mid - 1; 15 | } 16 | return {L, R}; 17 | } 18 | // count ocurences of s on t 19 | int busca_string(string &t) { 20 | pair range = {0, n - 1}; 21 | for (int i = 0; i < t.size(); i++) { 22 | range = busca(t, i, range); 23 | if (range.first == -1) return 0; 24 | } 25 | return range.second - range.first + 1; 26 | } -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Fenwick-Tree/Kd-Fenwick-Tree/kd_fenwick_tree.cpp: -------------------------------------------------------------------------------- 1 | const int MAX = 20; 2 | long long tree[MAX][MAX][MAX][MAX]; // insira o numero de dimensoes aqui 3 | 4 | long long query(vector s, int pos = 0) { // s eh a coordenada 5 | long long sum = 0; 6 | while (s[pos] >= 0) { 7 | if (pos < (int)s.size() - 1) { 8 | sum += query(s, pos + 1); 9 | } else { 10 | sum += tree[s[0]][s[1]][s[2]][s[3]]; 11 | // atualizar se mexer no numero de dimensoes 12 | } 13 | s[pos] = (s[pos] & (s[pos] + 1)) - 1; 14 | } 15 | return sum; 16 | } 17 | 18 | void update(vector s, int v, int pos = 0) { 19 | while (s[pos] < MAX) { 20 | if (pos < (int)s.size() - 1) { 21 | update(s, v, pos + 1); 22 | } else { 23 | tree[s[0]][s[1]][s[2]][s[3]] += v; 24 | // atualizar se mexer no numero de dimensoes 25 | } 26 | s[pos] |= s[pos] + 1; 27 | } 28 | } -------------------------------------------------------------------------------- /Codigos/String/Aho-Corasick/README.md: -------------------------------------------------------------------------------- 1 | # [Aho-Corasick](aho_corasick.cpp) 2 | 3 | Muito parecido com uma Trie, porém muito mais poderoso. O autômato de Aho-Corasick é um autômato finito determinístico que pode ser construído a partir de um conjunto de padrões. Nesse autômato, para qualquer nodo $u$ do autômato e qualquer caractere $c$ do alfabeto, é possível transicionar de $u$ usando o caractere $c$. 4 | 5 | A transição é feita por uma aresta direta de $u$ pra $v$, se a aresta de $u$ pra $v$ estiver marcada com o caractere $c$. Caso contrário, a transição de $u$ com o caractere $c$ segue a transição de $link(u)$ com o caractere $c$. 6 | 7 | **Definição**: $link(u)$ é um nodo $v$, tal que o prefixo do autômato até $v$ é sufixo de $u$, e esse prefixo é o maior possível. Ou seja, $link(u)$ é o maior prefixo do autômato que é sufixo de $u$. Com apenas um padrão inserido, o autômato de Aho-Corasick equivale à Prefix Function (KMP). 8 | 9 | No código, `cur` é o próximo nodo a ser criado. A root é o nodo $1$. 10 | -------------------------------------------------------------------------------- /Codigos/Grafos/Caminho-Euleriano/Caminho-Euleriano-Direcionado/README.md: -------------------------------------------------------------------------------- 1 | # [Caminho Euleriano (Grafo Direcionado)](directed_eulerian_path.cpp) 2 | 3 | Algoritmo para encontrar um caminho euleriano em um grafo direcionado em $\mathcal{O}(V + E)$. O algoritmo também encontrará um ciclo euleriano se o mesmo existir. Se nem um ciclo nem um caminho euleriano existir, o algoritmo retornará um vetor vazio. 4 | 5 | **Definição**: Um caminho euleriano é um caminho que passa por todas as arestas de um grafo exatamente uma vez. Um ciclo euleriano é um caminho euleriano que começa e termina no mesmo vértice. A condição de existência de um ciclo euleriano (em um grafo direcionado) é que todos os vértices do grafo possuam grau de entrada e saída iguais. A condição de existência de um caminho euleriano (em um grafo direcionado) é que o grafo possua exatamente dois vértices com grau de entrada e saída diferentes, sendo um deles o vértice de início (`deg_in[u] == deg_out[u] - 1`) e o outro o vértice de término (`deg_out[v] == deg_in[v] - 1`). -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Dirichlet-Convolution/Dirichlet-Convolution/dirichlet_convolution.cpp: -------------------------------------------------------------------------------- 1 | template 2 | vector dirichlet(const vector &f, const vector &g) { 3 | int n = int(max(f.size(), g.size())); 4 | vector primes, spf(n, 1), cnt(n); 5 | vector ans(n); 6 | ans[1] = (T)f[1] * g[1]; 7 | for (int i = 2; i < n; i++) { 8 | if (spf[i] == 1) { 9 | spf[i] = i; 10 | primes.emplace_back(i); 11 | cnt[i] = i; 12 | } 13 | 14 | for (auto p : primes) { 15 | if (i * p >= n) break; 16 | spf[i * p] = p; 17 | if (spf[i] == p) { 18 | cnt[i * p] = cnt[i] * p; 19 | break; 20 | } else cnt[i * p] = p; 21 | } 22 | 23 | if (i == cnt[i]) 24 | for (int j = 1; j <= cnt[i]; j *= spf[i]) ans[i] += (T)f[j] * g[cnt[i] / j]; 25 | else ans[i] = (T)ans[i / cnt[i]] * ans[cnt[i]]; 26 | } 27 | return ans; 28 | } 29 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Esparsa/README.md: -------------------------------------------------------------------------------- 1 | # [Segment Tree Esparsa](seg_tree_sparse.cpp) 2 | 3 | Segment Tree Esparsa, ou seja, não armazena todos os nodos da árvore, apenas os necessários, dessa forma ela suporta operações em intervalos arbitrários. A construção é $\mathcal{O}(1)$ e as operações de consulta e update são $\mathcal{O}(\log L)$, onde $L$ é o tamanho do intervalo. A implementação suporta operações de consulta em intervalo e update pontual. Está implementada para soma, mas pode ser facilmente modificada para outras operações. 4 | 5 | Para usar, declarar `SegTree st` para suportar updates e queries em posições de `L` a `R`. `L` e `R` podem inclusive ser negativos. 6 | 7 | **Dica**: No construtor da Seg Tree, fazer `t.reserve(MAX); Lc.reserve(MAX); Rc.reserve(MAX);` pode ajudar bastante no runtime, pois aloca espaço para os vetores e evita muitas realocações durante a execução. Nesse caso, `MAX` é geralmente $\mathcal{O}(Q \cdot \log L)$, onde $Q$ é o número de queries e $L$ é o tamanho do intervalo. -------------------------------------------------------------------------------- /Codigos/Paradigmas/Divide-and-Conquer/dc.cpp: -------------------------------------------------------------------------------- 1 | namespace DC { 2 | vi dp_before, dp_cur; 3 | void compute(int l, int r, int optl, int optr) { 4 | if (l > r) return; 5 | int mid = (l + r) >> 1; 6 | pair best = {0, -1}; // {INF, -1} se quiser minimizar 7 | for (int i = optl; i <= min(mid, optr); i++) { 8 | // min() se quiser minimizar 9 | best = max(best, {(i ? dp_before[i - 1] : 0) + query(i, mid), i}); 10 | } 11 | dp_cur[mid] = best.first; 12 | int opt = best.second; 13 | compute(l, mid - 1, optl, opt); 14 | compute(mid + 1, r, opt, optr); 15 | } 16 | 17 | ll solve(int n, int k) { 18 | dp_before.assign(n + 5, 0); 19 | dp_cur.assign(n + 5, 0); 20 | for (int i = 0; i < n; i++) dp_before[i] = query(0, i); 21 | for (int i = 1; i < k; i++) { 22 | compute(0, n - 1, 0, n - 1); 23 | dp_before = dp_cur; 24 | } 25 | return dp_before[n - 1]; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /Codigos/Grafos/2-SAT/README.md: -------------------------------------------------------------------------------- 1 | # [2-SAT](2_sat.cpp) 2 | 3 | Algoritmo que resolve problema do 2-SAT. No 2-SAT, temos um conjunto de variáveis booleanas e cláusulas lógicas, onde cada cláusula é composta por duas variáveis. O problema é determinar se existe uma configuração das variáveis que satisfaça todas as cláusulas. O problema se transforma em um problema de encontrar as componentes fortemente conexas de um grafo direcionado, que resolvemos em $\mathcal{O}(N + M)$ com o algoritmo de Kosaraju. Onde $N$ é o número de variáveis e $M$ é o número de cláusulas. 4 | 5 | A configuração da solução fica guardada no vetor `assignment`. 6 | 7 | Exemplos de uso: 8 | 9 | - `sat.add_or(x, y)` $\Leftrightarrow (x \lor y)$ 10 | - `sat.add_or(~x, y)` $\Leftrightarrow (\lnot x \lor y)$ 11 | - `sat.add_impl(x, y)` $\Leftrightarrow (x \rightarrow y)$ 12 | - `sat.add_and(x, ~y)` $\Leftrightarrow (x \land \lnot y)$ 13 | - `sat.add_xor(x, y)` $\Leftrightarrow (x \lor y) \land \lnot (x \land y)$ 14 | - `sat.add_equals(x, y)` $\Leftrightarrow (x \land y) \lor (\lnot x \land \lnot y)$ -------------------------------------------------------------------------------- /Codigos/String/Suffix-Automaton/README.md: -------------------------------------------------------------------------------- 1 | # [Suffix Automaton](suffix_automaton.cpp) 2 | 3 | Constrói o autômato de sufixos de uma string $S$ em $\mathcal{O}(|S|)$ de forma online. 4 | 5 | - `len[u]` é o tamanho da maior string na classe de equivalência de `u`. 6 | - `lnk[u]` é o nodo que representa o maior sufixo de `u` que não pertence a classe de equivalência de `u`. 7 | - `to[u]` é um array que representa as possivéis transições de um nodo `u`. 8 | - `cnt[u]` é um array que conta para cada classe de equivalência quantas ocorrências essas substrings tem. 9 | - `where[i]` diz em qual nodo do autômato a substring $s[0..i]$ está. 10 | 11 | Por definição, `len[lca(u, v)]` diz o tamanho da maior substring que é sufixo de `u` e `v` ao mesmo tempo, ou seja, é o longest common suffix. 12 | 13 | Algumas aplicações estão no código, é importante notar que essas aplicações funcionam de maneira **offline**, ou seja, uma vez settada a string no autômato, não se deve fazer inserts adicionais de caracteres. 14 | 15 | Para outras possíveis aplicações, consulte a Suffix Tree. -------------------------------------------------------------------------------- /Codigos/String/Hashing/Hashing/README.md: -------------------------------------------------------------------------------- 1 | # [Hashing](hashing.cpp) 2 | 3 | Hashing polinomial para testar igualdade de strings (ou de vetores). Requer precomputar as potências de um primo, como indicado na função `precalc`. A implementação está com dois MODS e usa a primitiva `Mint`, a escolha de usar apenas um MOD ou não usar o `Mint` vai da sua preferência ou necessidade, se não usar o `Mint`, trate adequadamente as operações com aritmética modular. A construção é $\mathcal{O}(n)$ e a consulta é $\mathcal{O}(1)$. 4 | 5 | **Obs**: lembrar de chamar a função `precalc`! 6 | 7 | Exemplo de uso: 8 | 9 | ```cpp 10 | string s = "abacabab"; 11 | Hashing h(s); 12 | cout << (h(0, 1) == h(2, 3)) << endl; // 0 13 | cout << (h(0, 1) == h(4, 5)) << endl; // 1 14 | cout << (h(0, 2) == h(4, 6)) << endl; // 1 15 | cout << (h(0, 3) == h(4, 7)) << endl; // 0 16 | cout << (h(0, 3) + h(4, n - 1) * pot[4] == h(0, n - 1)) << endl; // 1, da pra shiftar o hash 17 | string t = "abacabab"; 18 | Hashing h2(t); 19 | cout << (h() == h2()) << endl; // 1, pode comparar os hashes diretamente 20 | ``` 21 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Kadane/README.md: -------------------------------------------------------------------------------- 1 | # [Seg Tree Kadane](seg_tree_kadane.cpp) 2 | 3 | Implementação de uma Segment Tree que suporta update pontual e query de soma máxima de um subarray em um intervalo. A construção é $\mathcal{O}(n)$ e as operações de consulta e update são $\mathcal{O}(\log n)$. 4 | 5 | É uma Seg Tree normal, a magia está na função `merge` que é a função que computa a resposta do nodo atual. A ideia do `merge` da Seg Tree de Kadane de combinar respostas e informações já computadas dos filhos é muito útil e pode ser aplicada em muitos problemas. 6 | 7 | **Obs**: não considera o subarray vazio como resposta. 8 | 9 | **Dica**: A Seg Tree usa $4 \cdot n$ de memória pois cada nodo $p$ tem seus filhos $2 \cdot p$ (filho esquerdo) e $2 \cdot p + 1$ (filho direito). Há uma forma de indexar os nodos que usa $2 \cdot n$ de memória. Dado um nodo $p$ que representa o intervalo $[l, r]$, seu filho esquerdo é $p+1$ (e representa o intervalo $[l, mid]$) e seu filho direito é $p+2 \cdot (mid-l+1)$ (e representa o intervalo $[mid+1, r]$), onde $mid = (l+r)/2$. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Fenwick-Tree/Fenwick/fenwick_tree.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct FenwickTree { 3 | int n; 4 | vector bit, arr; 5 | FenwickTree(int _n = 0) : n(_n), bit(n), arr(n) { } 6 | FenwickTree(vector &v) : n(int(v.size())), bit(n), arr(v) { 7 | for (int i = 0; i < n; i++) bit[i] = arr[i]; 8 | for (int i = 0; i < n; i++) { 9 | int j = i | (i + 1); 10 | if (j < n) bit[j] = bit[j] + bit[i]; 11 | } 12 | } 13 | T pref(int x) { 14 | T res = T(); 15 | for (int i = x; i >= 0; i = (i & (i + 1)) - 1) res = res + bit[i]; 16 | return res; 17 | } 18 | T query(int l, int r) { 19 | if (l == 0) return pref(r); 20 | return pref(r) - pref(l - 1); 21 | } 22 | void update(int x, T d) { 23 | for (int i = x; i < n; i = i | (i + 1)) bit[i] = bit[i] + d; 24 | arr[x] = arr[x] + d; 25 | } 26 | void updateSet(int i, T d) { 27 | // funciona pra fenwick de soma 28 | update(i, d - arr[i]); 29 | arr[i] = d; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Operation-Stack/README.md: -------------------------------------------------------------------------------- 1 | # [Operation Stack](op_stack.cpp) 2 | 3 | Pilha que armazena o resultado do operatório dos itens (ou seja, dado uma pilha, responde qual é o elemento mínimo, por exemplo). A pilha possui a operação `get` que retorna o resultado do operatório dos itens da pilha em $\mathcal{O}(1)$ amortizado. Chamar o método `get` em uma pilha vazia é indefinido. 4 | 5 | A pilha é um template e recebe como argumentos o tipo dos itens e a função operatória. A função operatória deve receber dois argumentos do tipo dos itens e retornar um valor do mesmo tipo. 6 | 7 | Exemplo de como passar a função operatória para a pilha: 8 | 9 | ```cpp 10 | int f(int a, int b) { return a + b; } 11 | 12 | void test() { 13 | auto g = [](int a, int b) { return a ^ b; }; 14 | 15 | op_stack st; 16 | op_stack st2; 17 | 18 | st.push(1); 19 | st.push(1); 20 | st2.push(1); 21 | st2.push(1); 22 | cout << st.get() << endl; // 2 23 | cout << st2.get() << endl; // 0 24 | } 25 | ``` 26 | 27 | Pode ser tanto função normal quanto lambda. -------------------------------------------------------------------------------- /Codigos/Matemática/NTT/NTT/README.md: -------------------------------------------------------------------------------- 1 | # [NTT](ntt.cpp) 2 | 3 | Computa a multiplicação de polinômios com coeficientes inteiros módulo um número primo em $\mathcal{O}(N \cdot \log N)$. Exatamente o mesmo algoritmo da FFT, mas com inteiros. 4 | 5 | Não é qualquer módulo que funciona, aqui tem alguns que funcionam: 6 | 7 | 1. $998244353$ ($\approx 9 \times 10^8$): Para polinômios de tamanho até $2^{23}$. 8 | 2. $1004535809$ ($\approx 10^9$): Para polinômios de tamanho até $2^{21}$. 9 | 3. $1092616193$ ($\approx 10^9$): Para polinômios de tamanho até $2^{21}$. 10 | 4. $9223372036737335297$ ($\approx 9 \times 10^{18}$): Para polinômios de tamanho até $2^{24}$, se usar esse módulo, cuidado com os `ints`, use `long long`. 11 | 12 | **Obs**: Essa implementação usa a primitiva `Mint` desse Almanaque. Se você não quiser usar o `Mint`, basta substituir todas as ocorrências de `Mint` por `int` ou `long long` e tratar adequadamente as operações com aritmética modular. 13 | 14 | **Obs 2**: Nem tente usar $10^9 + 7$ ou $10^9 + 9$ como módulo, eles não funcionam. Para isso, pode-se tentar usar a NTT Big Modulo. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Operation-Deque/op_deque.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct op_deque { 3 | op_stack in, out; 4 | void push_back(T x) { in.push(x); } 5 | void push_front(T x) { out.push(x); } 6 | void work() { 7 | op_stack to; 8 | bool sw = false; 9 | if (in.empty()) sw = true, swap(in, out); 10 | int m = in.size(); 11 | for (int i = 0; i < m / 2; i++) to.push(in.top()), in.pop(); 12 | while (in.size()) out.push(in.top()), in.pop(); 13 | while (to.size()) in.push(to.top()), to.pop(); 14 | if (sw) swap(in, out); 15 | } 16 | T pop_front() { 17 | if (out.empty()) work(); 18 | T ret = out.top(); 19 | out.pop(); 20 | return ret; 21 | } 22 | T pop_back() { 23 | if (in.empty()) work(); 24 | T ret = in.top(); 25 | in.pop(); 26 | return ret; 27 | } 28 | T get() { 29 | if (in.empty()) return out.get(); 30 | if (out.empty()) return in.get(); 31 | return OP(in.get(), out.get()); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /Codigos/Primitivas/Ponto-2D/point2d.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct point { 3 | T x, y; 4 | point(T _x = 0, T _y = 0) : x(_x), y(_y) { } 5 | 6 | using p = point; 7 | 8 | p operator*(const T o) { return p(o * x, o * y); } 9 | p operator-(const p o) { return p(x - o.x, y - o.y); } 10 | p operator+(const p o) { return p(x + o.x, y + o.y); } 11 | T operator*(const p o) { return x * o.x + y * o.y; } 12 | T operator^(const p o) { return x * o.y - y * o.x; } 13 | bool operator<(const p o) const { return (x == o.x) ? y < o.y : x < o.x; } 14 | bool operator==(const p o) const { return (x == o.x) and (y == o.y); } 15 | bool operator!=(const p o) const { return (x != o.x) or (y != o.y); } 16 | 17 | T dist2(const p o) { 18 | T dx = x - o.x, dy = y - o.y; 19 | return dx * dx + dy * dy; 20 | } 21 | 22 | friend ostream &operator<<(ostream &out, const p &a) { 23 | return out << "(" << a.x << "," << a.y << ")"; 24 | } 25 | friend istream &operator>>(istream &in, p &a) { return in >> a.x >> a.y; } 26 | }; 27 | 28 | using pt = point; -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU-Rollback/rollback_dsu.cpp: -------------------------------------------------------------------------------- 1 | struct Rollback_DSU { 2 | vector par, sz; 3 | stack>> changes; 4 | void build(int n) { 5 | par.assign(n, 0); 6 | sz.assign(n, 1); 7 | iota(par.begin(), par.end(), 0); 8 | while (changes.size()) changes.pop(); 9 | changes.emplace(); 10 | } 11 | int find(int a) { return a == par[a] ? a : find(par[a]); } 12 | void checkpoint() { changes.emplace(); } 13 | void change(int &a, int b) { 14 | changes.top().emplace(a, a); 15 | a = b; 16 | } 17 | bool unite(int a, int b) { 18 | a = find(a), b = find(b); 19 | if (a == b) return false; 20 | if (sz[a] < sz[b]) swap(a, b); 21 | change(par[b], a); 22 | change(sz[a], sz[a] + sz[b]); 23 | return true; 24 | } 25 | void rollback() { 26 | while (changes.top().size()) { 27 | auto [a, b] = changes.top().top(); 28 | a = b; 29 | changes.top().pop(); 30 | } 31 | changes.pop(); 32 | } 33 | }; -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Dirichlet-Convolution/Dirichlet-Inverse-Prefix/README.md: -------------------------------------------------------------------------------- 1 | # [Dirichlet Inverse Prefix](dirichlet_inverse_prefix.cpp) 2 | 3 | Dadas três funções aritméticas $f$, $F$ e $f^{-1}$ com valores computados para $1 \le i \le N^{\frac{2}{3}}$, em que $F(i) = \sum_{j=1}^{i} f(j)$ e $f^{-1}$ é a inversa de Dirichlet de $f$, obtém-se 4 | $F^{-1}(\lfloor \tfrac{n}{i} \rfloor) = \sum_{j=1}^{\lfloor \frac{n}{i} \rfloor} f^{-1}(j)$ 5 | para todo $1 \le i \le N^{\frac{1}{3}}$ em $\mathcal{O}(N^{\frac{2}{3}})$. Para os demais $N^{\frac{2}{3}}$ valores, basta calcular 6 | $F^{-1}(i) = \sum_{j=1}^{i} f^{-1}(j)$ usando soma de prefixo. 7 | 8 | Para atingir essa complexidade, inicialize a estrutura com $T = N^{\frac{2}{3}}$ e realize as pré-computações necessárias para que todas as funções auxiliares respondam em $\mathcal{O}(1)$. 9 | 10 | O código utiliza a primitiva `Mint` para realizar operações modulares de forma eficiente. 11 | 12 | ## Funções utilizadas no método `Solve` 13 | 14 | - `f(x)`: retorna o valor de $f(x)$. 15 | - `F(x)`: retorna o valor de $\sum_{j=1}^{x} f(j)$. 16 | - `g(x)`: retorna o valor de $f^{-1}(x)$. 17 | -------------------------------------------------------------------------------- /LaTeX/chapters/01-cpp/constantes.tex: -------------------------------------------------------------------------------- 1 | \subsection{Constantes em C++} 2 | 3 | \begin{center} 4 | \begin{tabular}{|c|c|c|} 5 | \hline 6 | Constante & Nome em \texttt{C++} & Valor \\ 7 | \hline 8 | $\pi$ & \texttt{M\_PI} & 3.141592\ldots \\ 9 | \hline 10 | $\pi / 2$ & \texttt{M\_PI\_2} & 1.570796\ldots \\ 11 | \hline 12 | $\pi / 4$ & \texttt{M\_PI\_4} & 0.785398\ldots \\ 13 | \hline 14 | $1 / \pi$ & \texttt{M\_1\_PI} & 0.318309\ldots \\ 15 | \hline 16 | $2 / \pi$ & \texttt{M\_2\_PI} & 0.636619\ldots \\ 17 | \hline 18 | $2 / \sqrt{\pi}$ & \texttt{M\_2\_SQRTPI} & 1.128379\ldots \\ 19 | \hline 20 | $\sqrt{2}$ & \texttt{M\_SQRT2} & 1.414213\ldots \\ 21 | \hline 22 | $1 / \sqrt{2}$ & \texttt{M\_SQRT1\_2} & 0.707106\ldots \\ 23 | \hline 24 | $e$ & \texttt{M\_E} & 2.718281\ldots \\ 25 | \hline 26 | $\log_2{e}$ & \texttt{M\_LOG2E} & 1.442695\ldots \\ 27 | \hline 28 | $\log_{10}{e}$ & \texttt{M\_LOG10E} & 0.434294\ldots \\ 29 | \hline 30 | $\ln{2}$ & \texttt{M\_LN2} & 0.693147\ldots \\ 31 | \hline 32 | $\ln{10}$ & \texttt{M\_LN10} & 2.302585\ldots \\ 33 | \hline 34 | \end{tabular} 35 | \end{center} 36 | -------------------------------------------------------------------------------- /Codigos/Grafos/Shortest-Paths/Dial/dial.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | const int INF = 1e9; 3 | // D é o maior peso + 1 4 | const int D = 61; 5 | 6 | int n; 7 | vector> adj[N]; 8 | 9 | vector dial(int s) { 10 | vector dist(n, INF); 11 | vector> q(D); 12 | dist[s] = 0; 13 | q[0].push_back(s); 14 | int prev = -1; 15 | while (true) { 16 | int x = -1; 17 | for (int i = 1; i <= D; i++) { 18 | int cur = (prev + i) % D; 19 | if (!q[cur].empty()) { 20 | x = cur; 21 | break; 22 | } 23 | } 24 | if (x == -1) break; 25 | prev = x; 26 | while (!q[x].empty()) { 27 | int u = q[x].back(); 28 | q[x].pop_back(); 29 | if (x != dist[u] % D) continue; 30 | for (auto [w, v] : adj[u]) { 31 | int d = dist[u] + w; 32 | if (d < dist[v]) { 33 | q[d % D].push_back(v); 34 | dist[v] = d; 35 | } 36 | } 37 | } 38 | } 39 | return dist; 40 | } 41 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU-Bipartido/bipartite_dsu.cpp: -------------------------------------------------------------------------------- 1 | struct Bipartite_DSU { 2 | vector par, sz, c, bip; 3 | bool all_bipartite; 4 | void build(int n) { 5 | par.assign(n, 0); 6 | iota(par.begin(), par.end(), 0); 7 | sz.assign(n, 1); 8 | c.assign(n, 0); 9 | bip.assign(n, 1); 10 | all_bipartite = 1; 11 | } 12 | int find(int a) { return a == par[a] ? a : find(par[a]); } 13 | int color(int a) { return a == par[a] ? c[a] : c[a] ^ color(par[a]); } 14 | bool bipartite(int a) { return bip[find(a)]; } 15 | bool unite(int a, int b) { 16 | bool equal_color = color(a) == color(b); 17 | a = find(a), b = find(b); 18 | if (a == b) { 19 | if (equal_color) { 20 | bip[a] = 0; 21 | all_bipartite = 0; 22 | } 23 | return false; 24 | } 25 | if (sz[a] < sz[b]) swap(a, b); 26 | par[b] = a; 27 | sz[a] += sz[b]; 28 | if (equal_color) c[b] = 1; 29 | bip[a] &= bip[b]; 30 | all_bipartite &= bip[a]; 31 | return true; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/XOR-Trie/xor_trie.cpp: -------------------------------------------------------------------------------- 1 | struct XorTrie { 2 | const int bits = 30; 3 | vector> go; 4 | int root = 0, cnt = 1; 5 | void build(int n) { go.assign((n + 1) * bits, vector(2, -1)); } 6 | void insert(int x) { 7 | int v = root; 8 | for (int i = bits - 1; i >= 0; i--) { 9 | int b = x >> i & 1; 10 | if (go[v][b] == -1) go[v][b] = cnt++; 11 | v = go[v][b]; 12 | } 13 | } 14 | int max_xor(int x) { 15 | int v = root; 16 | int ans = 0; 17 | if (cnt <= 1) return -1; 18 | for (int i = bits - 1; i >= 0; i--) { 19 | int b = x >> i & 1; 20 | int good = go[v][!b]; 21 | int bad = go[v][b]; 22 | if (good != -1) { 23 | v = good; 24 | ans |= 1 << i; 25 | } else v = bad; 26 | } 27 | return ans; 28 | } 29 | int min_xor(int x) { 30 | int flipped = x ^ ((1 << bits) - 1); 31 | int query = max_xor(flipped); 32 | if (query == -1) return -1; 33 | return x ^ flipped ^ query; 34 | } 35 | } trie; 36 | -------------------------------------------------------------------------------- /Codigos/Grafos/Binary-Lifting/Binary-Lifting-LCA/binary_lifting_lca.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5, LG = 20; 2 | vector adj[N]; 3 | 4 | namespace bl { 5 | int t, up[N][LG], tin[N], tout[N]; 6 | 7 | void dfs(int u, int p = -1) { 8 | tin[u] = t++; 9 | for (int i = 0; i < LG - 1; i++) up[u][i + 1] = up[up[u][i]][i]; 10 | for (int v : adj[u]) 11 | if (v != p) { 12 | up[v][0] = u; 13 | dfs(v, u); 14 | } 15 | tout[u] = t++; 16 | } 17 | 18 | void build(int root) { 19 | t = 1; 20 | up[root][0] = root; 21 | dfs(root); 22 | } 23 | 24 | bool ancestor(int u, int v) { return tin[u] <= tin[v] && tout[u] >= tout[v]; } 25 | 26 | int lca(int u, int v) { 27 | if (ancestor(u, v)) return u; 28 | if (ancestor(v, u)) return v; 29 | for (int i = LG - 1; i >= 0; i--) 30 | if (!ancestor(up[u][i], v)) u = up[u][i]; 31 | return up[u][0]; 32 | } 33 | 34 | int kth(int u, int k) { 35 | for (int i = 0; i < LG; i++) 36 | if (k & (1 << i)) u = up[u][i]; 37 | return u; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Codigos/Grafos/HLD/HLD-Vértice/README.md: -------------------------------------------------------------------------------- 1 | # [Heavy-Light Decomposition (em Vértices)](hld.cpp) 2 | 3 | Técnica utilizada para decompor uma árvore em cadeias, e assim realizar operações de caminho e subárvore em $\mathcal{O}(\log N \cdot g(N))$, onde $g(N)$ é a complexidade da operação. Esta implementação suporta queries de soma e update de soma/atribuição, pois usa a estrutura de dados `Segment Tree Lazy` desse almanaque, fazendo assim com que updates e consultas sejam $\mathcal{O}(\log^2 N)$. A estrutura (bem como a operação feita nela) pode ser facilmente trocada, basta alterar o código da `Segment Tree Lazy`, ou ainda, utilizar outra estrutura de dados, como uma `Sparse Table`, caso você tenha queries de mínimo/máximo sem updates, por exemplo. Ao mudar a estrutura, pode ser necessário adaptar os métodos `query` e `update` da HLD. 4 | 5 | A HLD pode ser feita com os valores estando tanto nos vértices quanto nas arestas, essa implementação é feita com os valores nos **vértices**, para ter os valores nas arestas, consulte a implementação de HLD em arestas. 6 | 7 | A construção da HLD é feita em $\mathcal{O}(N + b(N))$, onde $b(N)$ é a complexidade de construir a estrutura de dados utilizada. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/LiChao-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [LiChao Tree](lichao_tree.cpp) 2 | 3 | Uma árvore de funções. Retorna o $f(x)$ máximo em um ponto $x$. 4 | 5 | Para retornar o mínimo, insira o negativo da função ($g(x) = -ax - b$) e pegue o negativo do resultado final. Outra opção é alterar a função de comparação da árvore, caso tenha familiaridade com a estrutura. 6 | 7 | Funciona para funções com a seguinte propriedade: sejam duas funções $f(x)$ e $g(x)$, uma vez que $f(x)$ passa a ganhar/perder para $g(x)$, $f(x)$ nunca mais passa a perder/ganhar para $g(x)$. Em outras palavras, $f(x)$ e $g(x)$ se intersectam no máximo uma vez. 8 | 9 | Essa implementação está pronta para usar função linear do tipo $f(x) = ax + b$. 10 | 11 | Sendo $L$ o tamanho do intervalo, a complexidade de consulta e inserção de funções é $\mathcal{O}(\log L)$. 12 | 13 | **Dica**: No construtor da LiChao Tree, fazer `tree.reserve(MAX); L.reserve(MAX); R.reserve(MAX);` pode ajudar bastante no runtime, pois aloca espaço para os vetores e evita muitas realocações durante a execução. Nesse caso, `MAX` é geralmente $\mathcal{O}(Q \cdot \log L)$, onde $Q$ é o número de queries e $L$ é o tamanho do intervalo. 14 | -------------------------------------------------------------------------------- /Codigos/Grafos/HLD/HLD-Aresta/README.md: -------------------------------------------------------------------------------- 1 | # [Heavy-Light Decomposition (em Arestas)](hld_edge.cpp) 2 | 3 | Técnica utilizada para decompor uma árvore em cadeias, e assim realizar operações de caminho e subárvore em $\mathcal{O}(\log N \cdot g(N))$, onde $g(N)$ é a complexidade da operação. Esta implementação suporta queries de soma e update de soma/atribuição, pois usa a estrutura de dados `Segment Tree Lazy` desse almanaque, fazendo assim com que updates e consultas sejam $\mathcal{O}(\log^2 N)$. A estrutura (bem como a operação feita nela) pode ser facilmente trocada, basta alterar o código da `Segment Tree Lazy`, ou ainda, utilizar outra estrutura de dados, como uma `Sparse Table`, caso você tenha queries de mínimo/máximo sem updates, por exemplo. Ao mudar a estrutura, pode ser necessário adaptar os métodos `query` e `update` da HLD. 4 | 5 | A HLD pode ser feita com os valores estando tanto nos vértices quanto nas arestas, essa implementação é feita com os valores nas **arestas**, para ter os valores nos vértices, consulte a implementação de HLD em vértices. 6 | 7 | A construção da HLD é feita em $\mathcal{O}(N + b(N))$, onde $b(N)$ é a complexidade de construir a estrutura de dados utilizada. -------------------------------------------------------------------------------- /LaTeX/chapters/02-teorico/problema-da-realizacao-de-grafos.tex: -------------------------------------------------------------------------------- 1 | \subsection{Problema da Realização de Grafos} 2 | Dada uma lista $\{d_0, d_1, d_2, ..., d_{n-1}\}$ de ordenação não crescente, deve-se dizer se existe um grafo simples (sem loops ou multiarestas) que tem como "lista de graus" a lista $d$ (caso exista, dizemos que $d$ é graphic). 3 | 4 | \subsubsection{Teorema de Erdős–Gallai} 5 | Uma lista $d$ é graphic se e somente se: 6 | \begin{equation*} 7 | \large 8 | \sum_{i = 0}^{k} d_{k} \le k(k-1) + \sum_{i = k+1}^{n-1}\min(k, d_{i}) 9 | \end{equation*} 10 | para todo 11 | \begin{equation*} 12 | \large 13 | k \in [0, n-1] 14 | \end{equation*}. 15 | 16 | \subsubsection{Teorema de Havel-Hakimi} 17 | Uma lista 18 | \begin{equation*} 19 | \large 20 | \{s, d_0, d_1, d_2 ..., d_{s-1}, d_s, d_{s+1}, ..., d_{n-2}, d_{n-1} \} 21 | \end{equation*} 22 | é graphic se e somente se a lista modificada 23 | \begin{equation*} 24 | \large 25 | \{d_0-1, d_1-1, d_2-1 ..., d_{s-1}-1, d_s, d_{s+1}, ..., d_{n-2}, d_{n-1} \} 26 | \end{equation*} 27 | também é. Isso permite a implementação de um algoritmo fácil para não só checar a realização de um grafo de lista $d$ mas também construir tal grafo. 28 | -------------------------------------------------------------------------------- /Codigos/Matemática/NTT/NTT/ntt.cpp: -------------------------------------------------------------------------------- 1 | const int MOD = mod; 2 | void ntt(vector &a, bool inv = 0) { 3 | int n = (int)a.size(); 4 | auto b = a; 5 | mint g = 1; 6 | while ((g ^ (MOD / 2)) == 1) g += 1; 7 | if (inv) g = mint(1) / g; 8 | for (int step = n / 2; step; step /= 2) { 9 | mint w = g ^ (MOD / (n / step)), wn = 1; 10 | for (int i = 0; i < n / 2; i += step) { 11 | for (int j = 0; j < step; j++) { 12 | auto u = a[2 * i + j], v = wn * a[2 * i + j + step]; 13 | b[i + j] = u + v; 14 | b[i + n / 2 + j] = u - v; 15 | } 16 | wn = wn * w; 17 | } 18 | swap(a, b); 19 | } 20 | if (inv) { 21 | mint invn = mint(1) / n; 22 | for (int i = 0; i < n; i++) a[i] *= invn; 23 | } 24 | } 25 | 26 | vector multiply(vector a, vector b) { 27 | int n = (int)a.size(), m = (int)b.size(); 28 | int t = n + m - 1, sz = 1; 29 | while (sz < t) sz <<= 1; 30 | a.resize(sz), b.resize(sz); 31 | ntt(a, 0), ntt(b, 0); 32 | for (int i = 0; i < sz; i++) a[i] *= b[i]; 33 | ntt(a, 1); 34 | while ((int)a.size() > t) a.pop_back(); 35 | return a; 36 | } 37 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Sparse-Table/Disjoint-Sparse-Table/dst.cpp: -------------------------------------------------------------------------------- 1 | struct DisjointSparseTable { 2 | int n, LG; 3 | vector> st; 4 | ll merge(ll a, ll b) { return a + b; } 5 | const ll neutral = 0; 6 | void build(const vector &v) { 7 | int sz = (int)v.size(); 8 | n = 1, LG = 1; 9 | while (n < sz) n <<= 1, LG++; 10 | st = vector>(LG, vector(n)); 11 | for (int i = 0; i < n; i++) st[0][i] = i < sz ? v[i] : neutral; 12 | for (int i = 1; i < LG - 1; i++) { 13 | for (int j = (1 << i); j < n; j += (1 << (i + 1))) { 14 | st[i][j] = st[0][j]; 15 | st[i][j - 1] = st[0][j - 1]; 16 | for (int k = 1; k < (1 << i); k++) { 17 | st[i][j + k] = merge(st[i][j + k - 1], st[0][j + k]); 18 | st[i][j - 1 - k] = merge(st[0][j - k - 1], st[i][j - k]); 19 | } 20 | } 21 | } 22 | } 23 | void build(ll *bg, ll *en) { build(vector(bg, en)); } 24 | ll query(int l, int r) { 25 | if (l == r) return st[0][l]; 26 | int i = 31 - __builtin_clz(l ^ r); 27 | return merge(st[i][l], st[i][r]); 28 | } 29 | } dst; -------------------------------------------------------------------------------- /Codigos/Grafos/Centroids/Centroid-Decomposition/centroid_decomposition.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | 3 | int sz[N], par[N]; 4 | bool rem[N]; 5 | vector dis[N]; 6 | vector adj[N]; 7 | 8 | int dfs_sz(int u, int p) { 9 | sz[u] = 1; 10 | for (int v : adj[u]) 11 | if (v != p && !rem[v]) sz[u] += dfs_sz(v, u); 12 | return sz[u]; 13 | } 14 | 15 | int centroid(int u, int p, int szn) { 16 | for (int v : adj[u]) 17 | if (v != p && !rem[v] && sz[v] > szn / 2) return centroid(v, u, szn); 18 | return u; 19 | } 20 | 21 | void dfs_dis(int u, int p, int d = 0) { 22 | dis[u].push_back(d); 23 | for (int v : adj[u]) 24 | if (v != p && !rem[v]) dfs_dis(v, u, d + 1); 25 | } 26 | 27 | void decomp(int u, int p) { 28 | int c = centroid(u, u, dfs_sz(u, u)); 29 | 30 | rem[c] = true; 31 | par[c] = p; 32 | 33 | dfs_dis(c, c); 34 | 35 | // Faz algo na subárvore de c 36 | 37 | for (int v : adj[c]) 38 | if (!rem[v]) decomp(v, c); 39 | } 40 | 41 | void build(int n) { 42 | for (int i = 0; i < n; i++) { 43 | rem[i] = false; 44 | dis[i].clear(); 45 | } 46 | decomp(0, -1); 47 | for (int i = 0; i < n; i++) reverse(dis[i].begin(), dis[i].end()); 48 | } -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Pollard-Rho/pollard_rho.cpp: -------------------------------------------------------------------------------- 1 | namespace PollardRho { 2 | mt19937 rng((uint32_t)chrono::steady_clock::now().time_since_epoch().count()); 3 | const ll P = 1e6 + 1; 4 | ll seq[P]; 5 | inline ll add_mod(ll x, ll y, ll m) { return (x += y) < m ? x : x - m; } 6 | inline ll mul_mod(ll a, ll b, ll m) { return (ll)((__int128)a * b % m); } 7 | ll rho(ll n) { 8 | if (n % 2 == 0) return 2; 9 | if (n % 3 == 0) return 3; 10 | ll x0 = rng() % n, c = rng() % n; 11 | while (1) { 12 | ll x = x0++, y = x, u = 1, v, t = 0; 13 | ll *px = seq, *py = seq; 14 | while (1) { 15 | *py++ = y = add_mod(mul_mod(y, y, n), c, n); 16 | *py++ = y = add_mod(mul_mod(y, y, n), c, n); 17 | if ((x = *px++) == y) break; 18 | v = u; 19 | u = mul_mod(u, abs(y - x), n); 20 | if (!u) return gcd(v, n); 21 | if (++t == 32) { 22 | t = 0; 23 | if ((u = gcd(u, n)) > 1 && u < n) return u; 24 | } 25 | } 26 | if (t && (u = gcd(u, n)) > 1 && u < n) return u; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Codigos/Grafos/Ciclos/Find-Negative-Cycle/find_negative_cycle.cpp: -------------------------------------------------------------------------------- 1 | struct NegativeCycleFinder { 2 | const ll INF = 1e18; 3 | int n; 4 | vector> edges; 5 | void build(int _n) { 6 | n = _n; 7 | edges.clear(); 8 | } 9 | void add_edge(int u, int v, ll w) { edges.emplace_back(u, v, w); } 10 | vector get_cycle() { 11 | vector d(n); 12 | vector p(n, -1); 13 | int x; 14 | for (int i = 0; i < n; ++i) { 15 | x = -1; 16 | for (auto [u, v, w] : edges) { 17 | if (d[u] < INF) { 18 | if (d[u] + w < d[v]) { 19 | d[v] = max(-INF, d[u] + w); 20 | p[v] = u; 21 | x = v; 22 | } 23 | } 24 | } 25 | } 26 | vector cycle; 27 | if (x != -1) { 28 | for (int i = 0; i < n; ++i) x = p[x]; 29 | for (int v = x;; v = p[v]) { 30 | cycle.push_back(v); 31 | if (v == x && cycle.size() > 1) break; 32 | } 33 | reverse(cycle.begin(), cycle.end()); 34 | } 35 | return cycle; 36 | } 37 | } finder; 38 | -------------------------------------------------------------------------------- /Codigos/Grafos/Matching/Hungaro/hungarian.cpp: -------------------------------------------------------------------------------- 1 | const ll INF = 1e18 + 18; 2 | 3 | vector> result; 4 | 5 | ll hungarian(int n, int m, vector> &A) { 6 | vector u(n + 1), v(m + 1), p(m + 1), way(m + 1); 7 | for (int i = 1; i <= n; i++) { 8 | p[0] = i; 9 | int j0 = 0; 10 | vector minv(m + 1, INF); 11 | vector used(m + 1, false); 12 | do { 13 | used[j0] = true; 14 | ll i0 = p[j0], delta = INF, j1; 15 | for (int j = 1; j <= m; j++) { 16 | if (!used[j]) { 17 | int cur = A[i0][j] - u[i0] - v[j]; 18 | if (cur < minv[j]) minv[j] = cur, way[j] = j0; 19 | if (minv[j] < delta) delta = minv[j], j1 = j; 20 | } 21 | } 22 | for (int j = 0; j <= m; j++) 23 | if (used[j]) u[p[j]] += delta, v[j] -= delta; 24 | else minv[j] -= delta; 25 | j0 = j1; 26 | } while (p[j0] != 0); 27 | do { 28 | int j1 = way[j0]; 29 | p[j0] = p[j1]; 30 | j0 = j1; 31 | } while (j0); 32 | } 33 | for (int i = 1; i <= m; i++) result.emplace_back(p[i], i); 34 | return -v[0]; 35 | } 36 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Merge-Sort-Tree/Merge-Sort-Tree/README.md: -------------------------------------------------------------------------------- 1 | # [Merge Sort Tree](mergesort_tree.cpp) 2 | 3 | Árvore muito semelhante a uma Segment Tree, mas ao invés de armazenar um valor em cada nodo, armazena um vetor ordenado. Permite realizar consultas do tipo: `count(L, R, A, B)` que retorna quantos elementos no intervalo $[L, R]$ estão no intervalo $[A, B]$ em $\mathcal{O}(\log^2 N)$. Em outras palavras, count(L, R, A, B) retorna quantos elementos $X$ existem no intervalo $[L, R]$ tal que $A \leq X \leq B$. 4 | 5 | **Obs**: o método `kth` presente nessa implementação encontra o k-ésimo elemento no intervalo $[L, R]$ em $\mathcal{O}(\log^3 N)$. É possível otimizar esse método para $\mathcal{O}(\log^2 N)$, basta se criar um vetor que possui pares da forma `[A[i], i]` e ordená-lo de acordo com o valor de `A[i]`, agora, construa a Merge Sort Tree com esse vetor e no merge faça a união mantendo os valores de `i` ordenados. Dessa forma, sua Merge Sort Tree guardará em um nodo que representa o intervalo $[L, R]$ os índices ordenados de todos os elementos que estão entre o $(L + 1)$-ésimo e o $(R + 1)$-ésimo menor elemento do vetor original. Assim, para encontrar o k-ésimo elemento no intervalo $[L, R]$ basta fazer uma busca binária semelhante a busca binária de encontrar $k$-ésimo menor elemento em uma Segment Tree. -------------------------------------------------------------------------------- /Codigos/Matemática/Eliminação-Gaussiana/Gauss-Mod-2/gauss_mod2.cpp: -------------------------------------------------------------------------------- 1 | const int M = 105; 2 | const int INF = 2; // nao tem que ser infinito ou um numero grande 3 | // so serve para indicar que tem infinitas solucoes 4 | 5 | int gauss(vector> a, int n, int m, bitset &ans) { 6 | vector where(m, -1); 7 | 8 | for (int col = 0, row = 0; col < m && row < n; col++) { 9 | for (int i = row; i < n; i++) { 10 | if (a[i][col]) { 11 | swap(a[i], a[row]); 12 | break; 13 | } 14 | } 15 | if (!a[row][col]) continue; 16 | where[col] = row; 17 | 18 | for (int i = 0; i < n; i++) 19 | if (i != row && a[i][col]) a[i] ^= a[row]; 20 | row++; 21 | } 22 | 23 | ans.reset(); 24 | for (int i = 0; i < m; i++) 25 | if (where[i] != -1) ans[i] = a[where[i]][m] / a[where[i]][i]; 26 | for (int i = 0; i < n; i++) { 27 | int sum = 0; 28 | for (int j = 0; j < m; j++) sum += ans[j] * a[i][j]; 29 | if (abs(sum - a[i][m]) > 0) return 0; // Sem solucao 30 | } 31 | 32 | for (int i = 0; i < m; i++) 33 | if (where[i] == -1) return INF; // Infinitas solucoes 34 | // Unica solucao (retornada no bitset ans) 35 | return 1; 36 | } 37 | -------------------------------------------------------------------------------- /Codigos/Geometria/Convex-Hull/convex_hull.cpp: -------------------------------------------------------------------------------- 1 | bool ccw(pt &p, pt &a, pt &b, bool include_collinear = 0) { 2 | pt p1 = a - p; 3 | pt p2 = b - p; 4 | return include_collinear ? (p2 ^ p1) <= 0 : (p2 ^ p1) < 0; 5 | } 6 | 7 | void sort_by_angle(vector &v) { // sorta o vetor por angulo em relacao ao pivo 8 | pt p0 = *min_element(begin(v), end(v)); 9 | sort(begin(v), end(v), [&](pt &l, pt &r) { // clockwise 10 | pt p1 = l - p0; 11 | pt p2 = r - p0; 12 | ll c1 = p1 ^ p2; 13 | return c1 < 0 || ((c1 == 0) && p0.dist2(l) < p0.dist2(r)); 14 | }); 15 | } 16 | 17 | vector convex_hull(vector v, bool include_collinear = 0) { 18 | int n = size(v); 19 | 20 | sort_by_angle(v); 21 | 22 | if (include_collinear) { 23 | for (int i = n - 2; i >= 0; i--) { // reverte o ultimo lado do poligono 24 | if (ccw(v[0], v[n - 1], v[i])) { 25 | reverse(begin(v) + i + 1, end(v)); 26 | break; 27 | } 28 | } 29 | } 30 | 31 | vector ch{v[0], v[1]}; 32 | for (int i = 2; i < n; i++) { 33 | while (ch.size() > 2 && 34 | (ccw(ch.end()[-2], ch.end()[-1], v[i], !include_collinear))) 35 | ch.pop_back(); 36 | ch.emplace_back(v[i]); 37 | } 38 | 39 | return ch; 40 | } 41 | -------------------------------------------------------------------------------- /LaTeX/chapters/02-teorico/teoria-dos-numeros.tex: -------------------------------------------------------------------------------- 1 | \subsection{Teoria dos números} 2 | 3 | \subsubsection{Pequeno teorema de Fermat} 4 | 5 | Se $p$ é um número primo e $a$ é um inteiro não divisível por $p$, então $a^{p-1} \equiv 1 \pmod{p}$. 6 | 7 | \subsubsection{Teorema de Euler} 8 | 9 | Se $m$ e $a$ são inteiros positivos coprimos, então $a^{\phi(m)} \equiv 1 \pmod{m}$, onde $\phi(m)$ é a função totiente de Euler. 10 | 11 | \subsubsection{Aritmética modular} 12 | 13 | Quando estamos trabalhando com aritmética módulo um número $p$, todos os valores existentes estão entre $[0, p-1]$. 14 | 15 | Algumas propriedades e equivalências úteis para usar aritmética modular em código são: 16 | 17 | \begin{itemize} 18 | \item $(a + b) \mod p \equiv ((a \mod p) + (b \mod p)) \mod p$ 19 | \item $(a - b) \mod p \equiv ((a \mod p) - (b \mod p)) \mod p$ 20 | \begin{itemize} 21 | \item Note que o resultado pode ser negativo, nesse caso é necessário adicionar $p$ ao resultado. De forma geral, geralmente fazemos $(a - b + p) \mod p$ (assumindo que $a$ e $b$ já estão no intervalo $[0, p-1]$). 22 | \end{itemize} 23 | \item $(a \cdot b) \mod p \equiv ((a \mod p) \cdot (b \mod p)) \mod p$ 24 | \item $a^b \mod p \equiv ((a \mod p)^b) \mod p$ 25 | \item $a^b \mod p \equiv ((a \mod p)^{(b \mod \phi(p))}) \mod p$ se $a$ e $p$ são coprimos 26 | \end{itemize} 27 | -------------------------------------------------------------------------------- /LaTeX/chapters/02-teorico/definicoes.tex: -------------------------------------------------------------------------------- 1 | \subsection{Definições} 2 | 3 | Algumas definições e termos importantes: 4 | 5 | \subsubsection{Funções} 6 | 7 | \begin{itemize} 8 | \item \textbf{Comutativa}: Uma função $f(x, y)$ é comutativa se $f(x, y) = f(y, x)$. 9 | \item \textbf{Associativa}: Uma função $f(x, y)$ é associativa se $f(x, f(y, z)) = f(f(x, y), z)$. 10 | \item \textbf{Idempotente}: Uma função $f(x, y)$ é idempotente se $f(x, x) = x$. 11 | \end{itemize} 12 | 13 | \subsubsection{Grafos} 14 | 15 | \begin{itemize} 16 | \item \textbf{Grafo}: Um grafo é um conjunto de vértices e um conjunto de arestas que conectam os vértices. 17 | \item \textbf{Grafo Conexo}: Um grafo é conexo se existe um caminho entre todos os pares de vértices. 18 | \item \textbf{Grafo Bipartido}: Um grafo é bipartido se é possível dividir os vértices em dois conjuntos disjuntos de forma que todas as arestas conectem um vértice de um conjunto com um vértice do outro conjunto, ou seja, não existem arestas que conectem vértices do mesmo conjunto. 19 | \item \textbf{Árvore}: Um grafo é uma árvore se ele é conexo e não possui ciclos. 20 | \item \textbf{Árvore Geradora Mínima (AGM)}: Uma árvore geradora mínima é uma árvore que conecta todos os vértices de um grafo e possui o menor custo possível, também conhecido como \textit{Minimum Spanning Tree (MST)}. 21 | \end{itemize} 22 | -------------------------------------------------------------------------------- /Codigos/Matemática/Eliminação-Gaussiana/Gauss-Mod-2/README.md: -------------------------------------------------------------------------------- 1 | # [Eliminação Gaussiana (MOD 2)](gauss_mod2.cpp) 2 | 3 | Método de eliminação gaussiana para resolução de sistemas lineares com coeficientes em $\mathbb{Z}_2$ (inteiros módulo 2), a complexidade é $\mathcal{O}(n^3 / \mathcal{w})$, onde $\mathcal{w}$ é a palavra do processador (geralmente 32 ou 64 bits, dependendo da arquitetura). 4 | 5 | No código, a constante $M$ deve ser definida como o `(número de variáveis + 1)`. 6 | 7 | A função `gauss` recebe como parâmetros: 8 | - `vector> a`: um vector de bitsets, representando as equações do sistema. Cada bitset tem tamanho $M$, onde o bit $j$ do bitset $i$ representa o coeficiente da variável $j$ na equação $i$. A última posição do bitset $i$ representa o resultado da equação $i$. 9 | - `n` e `m`: inteiros representando o número de equações e variáveis, respectivamente. 10 | - `bitset &ans`: um bitset de tamanho $M$, que será preenchido com a solução do sistema, caso exista. 11 | 12 | A função retorna: 13 | - `0`: se o sistema não tem solução. 14 | - `1`: se o sistema tem uma única solução. 15 | - `INF`: se o sistema tem infinitas soluções. Nesse caso, as variáveis em que `where[i] == -1` são as variáveis livres. Note que, pela natureza de $\mathbb{Z}_2$, o sistema não terá de fato infinitas soluções, mas sim $2^L$ soluções, onde $L$ é o número de variáveis livres. 16 | -------------------------------------------------------------------------------- /Codigos/Primitivas/Modular-Int/README.md: -------------------------------------------------------------------------------- 1 | # [Modular Int](mint.cpp) 2 | 3 | O Mint é uma classe que representa um número inteiro módulo número inteiro $\text{MOD}$. Ela é útil para evitar overflow em operações de multiplicação e exponenciação, e também para facilitar implementações. 4 | 5 | Ao usar o Mint, você deve passar os valores para ele **já modulados**, ou seja, valores entre $-\text{MOD}$ e $\text{MOD}-1$. O próprio Mint normaliza depois para ficar entre $0$ e $\text{MOD}-1$. 6 | 7 | Para lembrar as propriedades de aritmética modular, consulte a seção Teórico desse Almanaque. 8 | 9 | Para usar o Mint, basta criar um tipo com o valor de $\text{MOD}$ desejado. O valor de $\text{MOD}$ deve ser um número inteiro positivo, podendo ser tanto do tipo `int` quanto `long long`. 10 | 11 | ```cpp 12 | using mint = Mint<7>; 13 | // using mint = Mint<(ll)1e18 + 9> para long long 14 | mint a = 4, b = 3; 15 | mint c = a * b; // c.v == 5 16 | mint d = 1 / a; // d.v == 2, MOD deve ser primo para usar o operador de divisão 17 | mint e = a * d; // e.v == 1 18 | a = a + 2; // a.v == 6 19 | a = a + 3; // a.v == 2 20 | a = a ^ 5; // a.v == 4 21 | a = a - 6; // a.v == 5 22 | ``` 23 | 24 | **Obs**: para o operador de divisão, o Mint usa o inverso multiplicativo de $a$ baseado no Teorema de Euler (consulte o Teórico para mais detalhes), que é $a^{\text{MOD}-2}$. Portanto, o $\text{MOD}$ deve ser primo. 25 | -------------------------------------------------------------------------------- /Codigos/Grafos/Stoer–Wagner-Min-Cut/stoer_wagner.cpp: -------------------------------------------------------------------------------- 1 | const int MAXN = 555, INF = 1e9 + 7; 2 | 3 | int n, e, adj[MAXN][MAXN]; 4 | vector bestCut; 5 | 6 | int mincut() { 7 | int bestCost = INF; 8 | vector v[MAXN]; 9 | for (int i = 0; i < n; i++) v[i].assign(1, i); 10 | int w[MAXN], sel; 11 | bool exist[MAXN], added[MAXN]; 12 | memset(exist, true, sizeof(exist)); 13 | for (int phase = 0; phase < n - 1; phase++) { 14 | memset(added, false, sizeof(added)); 15 | memset(w, 0, sizeof(w)); 16 | for (int j = 0, prev; j < n - phase; j++) { 17 | sel = -1; 18 | for (int i = 0; i < n; i++) 19 | if (exist[i] && !added[i] && (sel == -1 || w[i] > w[sel])) sel = i; 20 | if (j == n - phase - 1) { 21 | if (w[sel] < bestCost) { 22 | bestCost = w[sel]; 23 | bestCut = v[sel]; 24 | } 25 | v[prev].insert(v[prev].end(), v[sel].begin(), v[sel].end()); 26 | for (int i = 0; i < n; i++) adj[prev][i] = adj[i][prev] += adj[sel][i]; 27 | exist[sel] = false; 28 | } else { 29 | added[sel] = true; 30 | for (int i = 0; i < n; i++) w[i] += adj[sel][i]; 31 | prev = sel; 32 | } 33 | } 34 | } 35 | return bestCost; 36 | } -------------------------------------------------------------------------------- /Codigos/String/Manacher/manacher.cpp: -------------------------------------------------------------------------------- 1 | struct Manacher { 2 | int n; 3 | ll count; 4 | vector d1, d2, man; 5 | ll solve(const string &s) { 6 | n = int(s.size()), count = 0; 7 | solve_odd(s); 8 | solve_even(s); 9 | man.assign(2 * n - 1, 0); 10 | for (int i = 0; i < n; i++) man[2 * i] = 2 * d1[i] - 1; 11 | for (int i = 0; i < n - 1; i++) man[2 * i + 1] = 2 * d2[i + 1]; 12 | return count; 13 | } 14 | void solve_odd(const string &s) { 15 | d1.assign(n, 0); 16 | for (int i = 0, l = 0, r = -1; i < n; i++) { 17 | int k = (i > r) ? 1 : min(d1[l + r - i], r - i + 1); 18 | while (0 <= i - k && i + k < n && s[i - k] == s[i + k]) k++; 19 | count += d1[i] = k--; 20 | if (i + k > r) l = i - k, r = i + k; 21 | } 22 | } 23 | void solve_even(const string &s) { 24 | d2.assign(n, 0); 25 | for (int i = 0, l = 0, r = -1; i < n; i++) { 26 | int k = (i > r) ? 0 : min(d2[l + r - i + 1], r - i + 1); 27 | while (0 <= i - k - 1 && i + k < n && s[i - k - 1] == s[i + k]) k++; 28 | count += d2[i] = k--; 29 | if (i + k > r) l = i - k - 1, r = i + k; 30 | } 31 | } 32 | bool query(int i, int j) { 33 | assert(man.size()); 34 | return man[i + j] >= j - i + 1; 35 | } 36 | } mana; -------------------------------------------------------------------------------- /Codigos/Matemática/Fatoração-e-Primos/Teste-Primalidade/Miller-Rabin/miller_rabin.cpp: -------------------------------------------------------------------------------- 1 | namespace MillerRabin { 2 | inline ll mul_mod(ll a, ll b, ll m) { return (ll)((__int128)a * b % m); } 3 | inline ll power(ll b, ll e, ll m) { 4 | ll r = 1; 5 | b = b % m; 6 | while (e > 0) { 7 | if (e & 1) r = mul_mod(r, b, m); 8 | b = mul_mod(b, b, m), e >>= 1; 9 | } 10 | return r; 11 | } 12 | inline bool composite(ll n, ll a, ll d, ll s) { 13 | ll x = power(a, d, n); 14 | if (x == 1 || x == n - 1 || a % n == 0) return false; 15 | for (int r = 1; r < s; r++) { 16 | x = mul_mod(x, x, n); 17 | if (x == n - 1) return false; 18 | } 19 | return true; 20 | } 21 | 22 | // com esses "primos", o teste funciona garantido para n <= 2^64 23 | int primes[] = {2, 325, 9375, 28178, 450775, 9780504, 1795265022}; 24 | 25 | // funciona para n <= 3*10^24 com os primos ate 41, mas tem que cuidar com overflow 26 | // int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41}; 27 | 28 | bool prime(ll n) { 29 | if (n <= 2 || (n % 2 == 0)) return n == 2; 30 | ll d = n - 1, r = 0; 31 | while (d % 2 == 0) d /= 2, r++; 32 | for (int a : primes) 33 | if (composite(n, a, d, r)) return false; 34 | return true; 35 | } 36 | } -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Dirichlet-Convolution/Dirichlet-Convolution-Prefix/README.md: -------------------------------------------------------------------------------- 1 | # [Dirichlet Convolution Prefix](dirichlet_convolution_prefix.cpp) 2 | 3 | Dadas duas funções aritméticas $f$ e $g$ com valores computados para $1 \le i \le N^{\frac{2}{3}}$, além de seus prefixos de soma $F$ e $G$ com valores computados para todo $\left\lfloor \frac{N}{i} \right\rfloor$ com $1 \le i \le N^{\frac{1}{3}}$, obtém-se o vetor $H$ tal que 4 | $H_i = \sum_{j=1}^{\lfloor \frac{n}{i} \rfloor} h(j)$ 5 | para todo $1 \le i \le N^{\frac{1}{3}}$ em $\mathcal{O}(N^{\frac{2}{3}})$, onde $h(n) = \sum_{d \mid n} f(d) \cdot g(\lfloor \tfrac{n}{d} \rfloor)$ é a convolução de Dirichlet de $f$ com $g$. Para atingir essa complexidade, inicialize a estrutura com $T = N^{2/3}$. 6 | 7 | Para obter os demais valores de $H$ (para $1 \le i \le N^{\frac{2}{3}}$) utilize a [convolução de Dirichlet linear](../Dirichlet-Convolution/dirichlet_convolution.cpp). 8 | 9 | O código usa a primitiva `Mint` para realizar operações modulares de forma eficiente. 10 | 11 | ## Funções utilizadas no método `Solve` 12 | 13 | - `f(x)`: retorna o valor de $f(x)$ em $\mathcal{O}(1)$. 14 | - `g(x)`: retorna o valor de $g(x)$ em $\mathcal{O}(1)$. 15 | - `F(x)`: retorna o valor de $\sum_{i=1}^{\lfloor \frac{n}{x} \rfloor} f(i)$ em $\mathcal{O}(1)$. 16 | - `G(x)`: retorna o valor de $\sum_{i=1}^{\lfloor \frac{n}{x} \rfloor} g(i)$ em $\mathcal{O}(1)$. 17 | -------------------------------------------------------------------------------- /Codigos/Matemática/XOR-Gauss/xor_gauss.cpp: -------------------------------------------------------------------------------- 1 | const int L = 60; 2 | struct Basis { 3 | ll B[L], R, last_bit; 4 | Basis() { memset(B, 0, sizeof B), R = 0; } 5 | ll reduce(ll x) { 6 | for (int i = L - 1; i >= 0; i--) { 7 | if ((x >> i) & 1) { 8 | if (B[i] != 0) { 9 | x ^= B[i]; 10 | } else { 11 | last_bit = i; 12 | return x; 13 | } 14 | } 15 | } 16 | // assert(x == 0); 17 | return 0; 18 | } 19 | bool insert(ll x) { 20 | x = reduce(x); 21 | if (x > 0) { 22 | R++; 23 | B[last_bit] = x; 24 | return true; 25 | } 26 | return false; 27 | } 28 | ll kth_smallest(ll k) { 29 | ll ans = 0; 30 | ll half = 1LL << (R - 1); 31 | for (int i = L - 1; i >= 0; i--) { 32 | if (B[i] != 0) { 33 | if ((ans >> i) & 1) { 34 | if (k > half) k -= half; 35 | else ans ^= B[i]; 36 | } else if (k > half) { 37 | ans ^= B[i]; 38 | k -= half; 39 | } 40 | half >>= 1; 41 | } 42 | } 43 | return ans; 44 | } 45 | ll kth_greatest(ll k) { return kth_smallest((1LL << R) - k + 1); } 46 | }; 47 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/Convex-Hull-Trick/Convex Hull Trick.cpp: -------------------------------------------------------------------------------- 1 | const ll INF = 1e18 + 18; 2 | bool op(ll a, ll b) { 3 | return a >= b; // either >= or <= 4 | } 5 | struct line { 6 | ll a, b; 7 | ll get(ll x) { return a * x + b; } 8 | ll intersect(line l) { 9 | return (l.b - b + a - l.a) / (a - l.a); // rounds up for integer 10 | // only 11 | } 12 | }; 13 | deque> fila; 14 | void add_line(ll a, ll b) { 15 | line nova = {a, b}; 16 | if (!fila.empty() && fila.back().first.a == a && fila.back().first.b == b) return; 17 | while (!fila.empty() && op(fila.back().second, nova.intersect(fila.back().first))) 18 | fila.pop_back(); 19 | ll x = fila.empty() ? -INF : nova.intersect(fila.back().first); 20 | fila.emplace_back(nova, x); 21 | } 22 | ll get_binary_search(ll x) { 23 | int esq = 0, dir = fila.size() - 1, r = -1; 24 | while (esq <= dir) { 25 | int mid = (esq + dir) / 2; 26 | if (op(x, fila[mid].second)) { 27 | esq = mid + 1; 28 | r = mid; 29 | } else { 30 | dir = mid - 1; 31 | } 32 | } 33 | return fila[r].first.get(x); 34 | } 35 | // O(1), use only when QUERIES are monotonic! 36 | ll get(ll x) { 37 | while (fila.size() >= 2 && op(x, fila[1].second)) fila.pop_front(); 38 | return fila.front().first.get(x); 39 | } 40 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/Exponenciação-de-Matriz/matrix_exp.cpp: -------------------------------------------------------------------------------- 1 | using mat = vector>; 2 | ll dp[100]; 3 | mat T; 4 | 5 | #define MOD 1000000007 6 | 7 | mat operator*(mat a, mat b) { 8 | mat res(a.size(), vector(b[0].size())); 9 | for (int i = 0; i < a.size(); i++) { 10 | for (int j = 0; j < b[0].size(); j++) { 11 | for (int k = 0; k < b.size(); k++) { 12 | res[i][j] += a[i][k] * b[k][j] % MOD; 13 | res[i][j] %= MOD; 14 | } 15 | } 16 | } 17 | return res; 18 | } 19 | 20 | mat operator^(mat a, ll k) { 21 | mat res(a.size(), vector(a.size())); 22 | for (int i = 0; i < a.size(); i++) res[i][i] = 1; 23 | while (k) { 24 | if (k & 1) res = res * a; 25 | a = a * a; 26 | k >>= 1; 27 | } 28 | return res; 29 | } 30 | 31 | // MUDA MUITO DE ACORDO COM O PROBLEMA 32 | // LEIA COMO FAZER O MAPEAMENTO NO README 33 | ll solve(ll exp, ll dim) { 34 | if (exp < dim) return dp[exp]; 35 | 36 | T.assign(dim, vi(dim)); 37 | // TO DO: Preencher a Matriz que vai ser 38 | // exponenciada T[0][1] = 1; T[1][0] = 1; 39 | // T[1][1] = 1; 40 | 41 | mat prod = T ^ exp; 42 | 43 | mat vec; 44 | vec.assign(dim, vi(1)); 45 | for (int i = 0; i < dim; i++) vec[i][0] = dp[i]; // Valores iniciais 46 | 47 | mat ans = prod * vec; 48 | return ans[0][0]; 49 | } 50 | -------------------------------------------------------------------------------- /Codigos/Grafos/Centro-e-Diametro/graph_center.cpp: -------------------------------------------------------------------------------- 1 | const int INF = 1e9 + 9; 2 | 3 | vector> adj; 4 | 5 | struct GraphCenter { 6 | int n, diam = 0; 7 | vector centros, dist, pai; 8 | int bfs(int s) { 9 | queue q; 10 | q.push(s); 11 | dist.assign(n + 5, INF); 12 | pai.assign(n + 5, -1); 13 | dist[s] = 0; 14 | int maxidist = 0, maxinode = 0; 15 | while (!q.empty()) { 16 | int u = q.front(); 17 | q.pop(); 18 | if (dist[u] >= maxidist) maxidist = dist[u], maxinode = u; 19 | for (int v : adj[u]) { 20 | if (dist[u] + 1 < dist[v]) { 21 | dist[v] = dist[u] + 1; 22 | pai[v] = u; 23 | q.push(v); 24 | } 25 | } 26 | } 27 | diam = max(diam, maxidist); 28 | return maxinode; 29 | } 30 | GraphCenter(int st = 0) : n(adj.size()) { 31 | int d1 = bfs(st); 32 | int d2 = bfs(d1); 33 | vector path; 34 | for (int u = d2; u != -1; u = pai[u]) path.push_back(u); 35 | int len = path.size(); 36 | if (len % 2 == 1) { 37 | centros.push_back(path[len / 2]); 38 | } else { 39 | centros.push_back(path[len / 2]); 40 | centros.push_back(path[len / 2 - 1]); 41 | } 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /LaTeX/chapters/02-teorico/sequencias-numericas.tex: -------------------------------------------------------------------------------- 1 | \subsection{Sequências numéricas} 2 | 3 | \subsubsection{Sequência de Fibonacci} 4 | 5 | Primeiros termos: \textbf{1, 1, 2, 3, 5, 8, 13, 21, 34, \ldots} 6 | 7 | Definição: 8 | 9 | \begin{equation*} 10 | \large 11 | F_0 = F_1 = 1 12 | \end{equation*} 13 | 14 | \begin{equation*} 15 | \large 16 | F_n = F_{n-1} + F_{n-2} 17 | \end{equation*} 18 | 19 | Matriz de recorrência: 20 | 21 | \begin{equation*} 22 | \large 23 | \begin{bmatrix} 24 | 0 & 1 \\ 25 | 1 & 1 26 | \end{bmatrix} 27 | \begin{bmatrix} 28 | F_{n-2} \\ 29 | F_{n-1} 30 | \end{bmatrix} 31 | = 32 | \begin{bmatrix} 33 | F_{n-1} \\ 34 | F_n 35 | \end{bmatrix} 36 | \end{equation*} 37 | 38 | \subsubsection{Sequência de Catalan} 39 | 40 | Primeiros termos: \textbf{1, 1, 2, 5, 14, 42, 132, 429, 1430, \ldots} 41 | 42 | Definição: 43 | 44 | \begin{equation*} 45 | \large 46 | C_0 = C_1 = 1 47 | \end{equation*} 48 | 49 | \begin{equation*} 50 | \large 51 | C_n = \sum_{i=0}^{n-1} C_i \cdot C_{n-1-i} 52 | \end{equation*} 53 | 54 | Definição analítica: 55 | 56 | \begin{equation*} 57 | \large 58 | C_n = \frac{1}{n+1} \binom{2n}{n} 59 | \end{equation*} 60 | 61 | Propriedades úteis: 62 | 63 | \begin{itemize} 64 | \item $C_n$ é o número de árvores binárias com $n+1$ folhas. 65 | \item $C_n$ é o número de sequências de parênteses bem formadas com $n$ pares de parênteses. 66 | \end{itemize} 67 | -------------------------------------------------------------------------------- /Codigos/Matemática/Eliminação-Gaussiana/Gauss/gauss.cpp: -------------------------------------------------------------------------------- 1 | const double EPS = 1e-9; 2 | const int INF = 2; // nao tem que ser infinito ou um numero grande 3 | // so serve para indicar que tem infinitas solucoes 4 | 5 | int gauss(vector> a, vector &ans) { 6 | int n = (int)a.size(); 7 | int m = (int)a[0].size() - 1; 8 | 9 | vector where(m, -1); 10 | for (int col = 0, row = 0; col < m && row < n; col++) { 11 | int sel = row; 12 | for (int i = row; i < n; i++) 13 | if (abs(a[i][col]) > abs(a[sel][col])) sel = i; 14 | if (abs(a[sel][col]) < EPS) continue; 15 | for (int i = col; i <= m; i++) swap(a[sel][i], a[row][i]); 16 | where[col] = row; 17 | 18 | for (int i = 0; i < n; i++) { 19 | if (i != row) { 20 | double c = a[i][col] / a[row][col]; 21 | for (int j = col; j <= m; j++) a[i][j] -= a[row][j] * c; 22 | } 23 | } 24 | row++; 25 | } 26 | 27 | ans.assign(m, 0); 28 | for (int i = 0; i < m; i++) 29 | if (where[i] != -1) ans[i] = a[where[i]][m] / a[where[i]][i]; 30 | for (int i = 0; i < n; i++) { 31 | double sum = 0; 32 | for (int j = 0; j < m; j++) sum += ans[j] * a[i][j]; 33 | if (abs(sum - a[i][m]) > EPS) return 0; 34 | } 35 | 36 | for (int i = 0; i < m; i++) 37 | if (where[i] == -1) return INF; 38 | return 1; 39 | } 40 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Iterativa/itseg_tree.cpp: -------------------------------------------------------------------------------- 1 | struct SegTree { 2 | ll merge(ll a, ll b) { return a + b; } 3 | const ll neutral = 0; 4 | inline int lc(int p) { return p * 2; } 5 | inline int rc(int p) { return p * 2 + 1; } 6 | int n; 7 | vector t; 8 | void build(int _n) { // pra construir com tamanho, mas vazia 9 | n = _n; 10 | t.assign(n * 2, neutral); 11 | } 12 | void build(const vector &v) { // pra construir com vector 13 | n = (int)v.size(); 14 | t.assign(n * 2, neutral); 15 | for (int i = 0; i < n; i++) t[i + n] = v[i]; 16 | for (int i = n - 1; i > 0; i--) t[i] = merge(t[lc(i)], t[rc(i)]); 17 | } 18 | void build(ll *bg, ll *en) { // pra construir com array de C 19 | build(vector(bg, en)); 20 | } 21 | ll query(int l, int r) { 22 | ll ansl = neutral, ansr = neutral; 23 | for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1) { 24 | if (l & 1) ansl = merge(ansl, t[l++]); 25 | if (r & 1) ansr = merge(t[--r], ansr); 26 | } 27 | return merge(ansl, ansr); 28 | } 29 | void update(int i, ll x, bool replace) { 30 | i += n; 31 | t[i] = replace ? x : merge(t[i], x); 32 | for (i >>= 1; i > 0; i >>= 1) t[i] = merge(t[lc(i)], t[rc(i)]); 33 | } 34 | void sumUpdate(int i, ll x) { update(i, x, 0); } 35 | void setUpdate(int i, ll x) { update(i, x, 1); } 36 | } seg; 37 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/XOR-Convolution/xor_convolution.cpp: -------------------------------------------------------------------------------- 1 | vector xor_convolution(vector A, vector B) { 2 | int n = int(A.size()); 3 | for (int rep = 0; rep < 2; rep++) { 4 | for (int len = n >> 1; len; len >>= 1) { 5 | for (int i = 0; i < n; i += len << 1) { 6 | for (int j = 0; j < len; j++) { 7 | int id = i + j; 8 | mint x = A[id]; 9 | mint y = A[id + len]; 10 | A[id] = x + y; 11 | A[id + len] = x - y; 12 | } 13 | } 14 | } 15 | swap(A, B); 16 | } 17 | vector ans(n); 18 | for (int i = 0; i < n; i++) ans[i] = A[i] * B[i]; 19 | for (int len = 1; len < n; len <<= 1) { 20 | for (int i = 0; i < n; i += len << 1) { 21 | for (int j = 0; j < len; j++) { 22 | int id = i + j; 23 | mint x = ans[id]; 24 | mint y = ans[id + len]; 25 | ans[id] = x + y; 26 | ans[id + len] = x - y; 27 | } 28 | } 29 | } 30 | return ans; 31 | } 32 | 33 | vector xor_multiply(vector A, vector B) { 34 | int N = 1; 35 | int n = int(max(A.size(), B.size())); 36 | while (N < n) N <<= 1; 37 | A.resize(N); 38 | B.resize(N); 39 | auto ans = xor_convolution(A, B); 40 | for (int i = 0; i < N; i++) ans[i] /= N; 41 | return ans; 42 | } 43 | -------------------------------------------------------------------------------- /Codigos/Grafos/Kosaraju/kosaraju.cpp: -------------------------------------------------------------------------------- 1 | namespace kosaraju { 2 | const int N = 1e5 + 5; 3 | int n, vis[N], root[N]; 4 | vector adj[N], inv[N], gc[N], topo; 5 | void add_edge(int u, int v) { 6 | adj[u].emplace_back(v); 7 | inv[v].emplace_back(u); 8 | } 9 | void toposort(int u) { 10 | vis[u] = 1; 11 | for (auto v : adj[u]) { 12 | if (vis[v]) continue; 13 | toposort(v); 14 | } 15 | topo.emplace_back(u); 16 | } 17 | void dfs(int u) { 18 | vis[u] = 1; 19 | for (auto v : inv[u]) { 20 | if (vis[v]) continue; 21 | root[v] = root[u]; 22 | dfs(v); 23 | } 24 | } 25 | void solve(int n) { 26 | fill(vis, vis + n, 0); 27 | topo.clear(); 28 | for (int i = 0; i < n; i++) 29 | if (!vis[i]) toposort(i); 30 | fill(vis, vis + n, 0); 31 | iota(root, root + n, 0); 32 | for (int i = n - 1; i >= 0; i--) 33 | if (!vis[topo[i]]) dfs(topo[i]); 34 | set> st; 35 | for (int u = 0; u < n; u++) { 36 | int ru = root[u]; 37 | for (int v : adj[u]) { 38 | int rv = root[v]; 39 | if (ru == rv) continue; 40 | if (!st.count(ii(ru, rv))) { 41 | gc[ru].emplace_back(rv); 42 | st.insert(ii(ru, rv)); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Codigos/Grafos/LCA/lca.cpp: -------------------------------------------------------------------------------- 1 | const int N = 5e5 + 5; 2 | int timer, tin[N]; 3 | vector adj[N]; 4 | vector> prof; 5 | 6 | struct SparseTable { 7 | int n, LG; 8 | using T = pair; 9 | vector> st; 10 | T merge(T a, T b) { return min(a, b); } 11 | const T neutral = {INT_MAX, -1}; 12 | void build(const vector &v) { 13 | n = (int)v.size(); 14 | LG = 32 - __builtin_clz(n); 15 | st = vector>(LG, vector(n)); 16 | for (int i = 0; i < n; i++) st[0][i] = v[i]; 17 | for (int i = 0; i < LG - 1; i++) 18 | for (int j = 0; j + (1 << i) < n; j++) 19 | st[i + 1][j] = merge(st[i][j], st[i][j + (1 << i)]); 20 | } 21 | T query(int l, int r) { 22 | if (l > r) return neutral; 23 | int i = 31 - __builtin_clz(r - l + 1); 24 | return merge(st[i][l], st[i][r - (1 << i) + 1]); 25 | } 26 | } st_lca; 27 | 28 | void et_dfs(int u, int p, int h) { 29 | tin[u] = timer++; 30 | prof.emplace_back(h, u); 31 | for (int v : adj[u]) { 32 | if (v != p) { 33 | et_dfs(v, u, h + 1); 34 | prof.emplace_back(h, u); 35 | } 36 | } 37 | timer++; 38 | } 39 | 40 | int lca(int u, int v) { 41 | int l = tin[u], r = tin[v]; 42 | if (l > r) swap(l, r); 43 | return st_lca.query(l, r).second; 44 | } 45 | 46 | void build() { 47 | timer = 0; 48 | prof.clear(); 49 | et_dfs(0, -1, 0); 50 | st_lca.build(prof); 51 | } -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Dirichlet-Convolution/Dirichlet-Inverse-Prefix/dirichlet_inverse_prefix.cpp: -------------------------------------------------------------------------------- 1 | struct DirichletInversePrefix { 2 | ll N; 3 | int T; 4 | vector init_pref, ans; 5 | vector vis; 6 | DirichletInversePrefix(ll n, int t, vector _init_pref) 7 | : N(n), T(t), init_pref(_init_pref) { 8 | vis.assign(n / T + 1, 0); 9 | ans.assign(n / T + 1, 0); 10 | } 11 | 12 | mint solve(ll n, ll floor_N, auto &&f, auto &&F, auto &&g) { 13 | if (n < int(init_pref.size())) { 14 | if (floor_N <= N / T) { 15 | vis[floor_N] = true; 16 | ans[floor_N] = init_pref[n]; 17 | } 18 | return init_pref[n]; 19 | } 20 | 21 | if (vis[floor_N]) return ans[floor_N]; 22 | 23 | vis[floor_N] = true; 24 | ans[floor_N] = 1; 25 | int j = 1; 26 | for (; (ll)j * j <= n; j++) { 27 | if (j > 1) ans[floor_N] -= solve(n / j, floor_N * j, f, F, g) * f(j); 28 | { ans[floor_N] -= g(j) * F(n / j); } 29 | } 30 | --j; 31 | ans[floor_N] += init_pref[j] * F(j); 32 | return ans[floor_N]; 33 | } 34 | 35 | vector solve(auto &&f, auto &&F, auto &&g) { 36 | if (N == 1) return vector(2, 1); 37 | vis.assign(N / T + 1, 0); 38 | ans.assign(N / T + 1, 0); 39 | for (int i = 1; i <= N / T; i++) 40 | if (!vis[i]) solve(N / i, i, f, F, g); 41 | return ans; 42 | } 43 | }; 44 | -------------------------------------------------------------------------------- /Codigos/Grafos/Ciclos/Find-Cycle/find_cycle.cpp: -------------------------------------------------------------------------------- 1 | const int MAXN = 1e6 + 6; 2 | 3 | vector adj[MAXN]; 4 | 5 | struct CycleFinder { 6 | int n; 7 | bool trivial; 8 | vector vis, par; 9 | int start = -1, end = -1; 10 | void build(int _n, bool _trivial = 1) { 11 | n = _n; 12 | trivial = _trivial; 13 | // trivial eh um flag que indica se o algoritmo deve aceitar ou nao 14 | // ciclos triviais, um ciclo trivial eh um ciclo de tamanho 1 ou 2 15 | } 16 | bool dfs(int u) { 17 | vis[u] = 1; 18 | for (int v : adj[u]) { 19 | if (vis[v] == 0) { 20 | par[v] = u; 21 | if (dfs(v)) return true; 22 | } else if (vis[v] == 1) { 23 | if (trivial || (par[u] != v && u != v)) { 24 | end = u; 25 | start = v; 26 | return true; 27 | } 28 | } 29 | } 30 | vis[u] = 2; 31 | return false; 32 | } 33 | vector get_cycle() { 34 | vis.assign(n, 0); 35 | par.assign(n, -1); 36 | for (int v = 0; v < n; v++) 37 | if (vis[v] == 0 && dfs(v)) break; 38 | vector cycle; 39 | if (start != -1) { 40 | cycle.emplace_back(start); 41 | for (int v = end; v != start; v = par[v]) cycle.emplace_back(v); 42 | cycle.emplace_back(start); 43 | reverse(cycle.begin(), cycle.end()); 44 | } 45 | return cycle; 46 | } 47 | } finder; 48 | -------------------------------------------------------------------------------- /Codigos/Paradigmas/Mo/Mo/mo.cpp: -------------------------------------------------------------------------------- 1 | typedef pair ii; 2 | int block_sz; // Better if 'const'; 3 | 4 | namespace mo { 5 | struct query { 6 | int l, r, idx; 7 | bool operator<(query q) const { 8 | int _l = l / block_sz; 9 | int _ql = q.l / block_sz; 10 | return ii(_l, _l & 1 ? -r : r) < ii(_ql, _ql & 1 ? -q.r : q.r); 11 | } 12 | }; 13 | vector queries; 14 | 15 | void build(int n) { 16 | block_sz = (int)sqrt(n); 17 | // TODO: initialize data structure 18 | } 19 | inline void add_query(int l, int r) { 20 | queries.push_back({l, r, (int)queries.size()}); 21 | } 22 | inline void remove(int idx) { 23 | // TODO: remove value at idx from data 24 | // structure 25 | } 26 | inline void add(int idx) { 27 | // TODO: add value at idx from data 28 | // structure 29 | } 30 | inline int get_answer() { 31 | // TODO: extract the current answer of the 32 | // data structure 33 | return 0; 34 | } 35 | 36 | vector run() { 37 | vector answers(queries.size()); 38 | sort(queries.begin(), queries.end()); 39 | int L = 0; 40 | int R = -1; 41 | for (query q : queries) { 42 | while (L > q.l) add(--L); 43 | while (R < q.r) add(++R); 44 | while (L < q.l) remove(L++); 45 | while (R > q.r) remove(R--); 46 | answers[q.idx] = get_answer(); 47 | } 48 | return answers; 49 | } 50 | 51 | }; 52 | -------------------------------------------------------------------------------- /Codigos/Matemática/Convolução/Subset-Convolution/subset_convolution.cpp: -------------------------------------------------------------------------------- 1 | vector subset_convolution(vector A, vector B) { 2 | int n = int(max(A.size(), B.size())); 3 | int N = 0; 4 | while ((1 << N) < n) N++; 5 | A.resize(1 << N), B.resize(1 << N); 6 | vector a(1 << N, vector(N + 1)), b(1 << N, vector(N + 1)); 7 | for (int i = 0; i < 1 << N; i++) { 8 | int popcnt = __builtin_popcount(i); 9 | a[i][popcnt] = A[i]; 10 | b[i][popcnt] = B[i]; 11 | } 12 | for (int j = 0; j < N; j++) { 13 | for (int i = 0; i < 1 << N; i++) { 14 | if (~i >> j & 1) continue; 15 | for (int popcnt = 0; popcnt <= N; popcnt++) { 16 | a[i][popcnt] += a[i ^ (1 << j)][popcnt]; 17 | b[i][popcnt] += b[i ^ (1 << j)][popcnt]; 18 | } 19 | } 20 | } 21 | vector c(1 << N, vector(N + 1)); 22 | for (int i = 0; i < 1 << N; i++) { 23 | for (int j = 0; j <= N; j++) 24 | for (int k = 0; k + j <= N; k++) c[i][j + k] += a[i][j] * b[i][k]; 25 | } 26 | for (int j = N - 1; j >= 0; j--) { 27 | for (int i = (1 << N) - 1; i >= 0; i--) { 28 | if (~i >> j & 1) continue; 29 | for (int popcnt = 0; popcnt <= N; popcnt++) 30 | c[i][popcnt] -= c[i ^ (1 << j)][popcnt]; 31 | } 32 | } 33 | vector ans(1 << N); 34 | for (int i = 0; i < 1 << N; i++) { 35 | int popcnt = __builtin_popcount(i); 36 | ans[i] = c[i][popcnt]; 37 | } 38 | return ans; 39 | } 40 | -------------------------------------------------------------------------------- /Codigos/String/Aho-Corasick/aho_corasick.cpp: -------------------------------------------------------------------------------- 1 | namespace aho { 2 | const int M = 3e5 + 1; 3 | const int K = 26; 4 | 5 | const char norm = 'a'; 6 | inline int get(int c) { return c - norm; } 7 | 8 | int next[M][K], link[M], out_link[M], par[M], cur = 2; 9 | char pch[M]; 10 | bool out[M]; 11 | vector output[M]; 12 | 13 | int node(int p, char c) { 14 | link[cur] = out_link[cur] = 0; 15 | par[cur] = p; 16 | pch[cur] = c; 17 | return cur++; 18 | } 19 | 20 | int T = 0; 21 | 22 | int insert(const string &s) { 23 | int u = 1; 24 | for (int i = 0; i < (int)s.size(); i++) { 25 | auto v = next[u][get(s[i])]; 26 | if (v == 0) next[u][get(s[i])] = v = node(u, s[i]); 27 | u = v; 28 | } 29 | out[u] = true; 30 | output[u].emplace_back(T); 31 | return T++; 32 | } 33 | 34 | int go(int u, char c); 35 | 36 | int get_link(int u) { 37 | if (link[u] == 0) link[u] = par[u] > 1 ? go(get_link(par[u]), pch[u]) : 1; 38 | return link[u]; 39 | } 40 | 41 | int go(int u, char c) { 42 | if (next[u][get(c)] == 0) next[u][get(c)] = u > 1 ? go(get_link(u), c) : 1; 43 | return next[u][get(c)]; 44 | } 45 | 46 | int exit(int u) { 47 | if (out_link[u] == 0) { 48 | int v = get_link(u); 49 | out_link[u] = (out[v] || v == 1) ? v : exit(v); 50 | } 51 | return out_link[u]; 52 | } 53 | 54 | bool matched(int u) { return out[u] || exit(u) > 1; } 55 | 56 | } -------------------------------------------------------------------------------- /LaTeX/chapters/02-teorico/analise-combinatoria.tex: -------------------------------------------------------------------------------- 1 | \subsection{Análise combinatória} 2 | 3 | \subsubsection{Fatorial} 4 | 5 | O fatorial de um número $n$ é o produto de todos os inteiros positivos menores ou iguais a $n$. 6 | 7 | O fatorial conta o número de permutações de $n$ elementos. 8 | 9 | \begin{equation*} 10 | \large 11 | n! = n \cdot (n-1)! 12 | \end{equation*} 13 | 14 | Em particular, $0! = 1$. 15 | 16 | \subsubsection{Combinação} 17 | 18 | Conta o número de maneiras de escolher $k$ elementos de um conjunto de $n$ elementos. 19 | 20 | \begin{equation*} 21 | \large 22 | \binom{n}{k} = \frac{n!}{k! \cdot (n-k)!} 23 | \end{equation*} 24 | 25 | \subsubsection{Arranjo} 26 | 27 | Conta o número de maneiras de escolher $k$ elementos de um conjunto de $n$ elementos, onde a ordem importa. 28 | 29 | \begin{equation*} 30 | \large 31 | P(n, k) = \frac{n!}{(n-k)!} 32 | \end{equation*} 33 | 34 | \subsubsection{Estrelas e barras} 35 | 36 | Conta o número de maneiras de distribuir $n$ elementos idênticos em $k$ recipientes distintos. 37 | 38 | \begin{equation*} 39 | \large 40 | \binom{n+k-1}{k-1} 41 | \end{equation*} 42 | 43 | \subsubsection{Princípio da inclusão-exclusão} 44 | 45 | O princípio da inclusão-exclusão é uma técnica para contar o número de elementos em uma união de conjuntos. 46 | 47 | \begin{align*} 48 | \left| \bigcup_{i=1}^{n} A_i \right| 49 | &= \sum_{k=1}^{n} (-1)^{k+1} 50 | \sum_{\substack{1 \leq i_1 < \cdots < i_k \leq n}} 51 | \left| A_{i_1} \cap \cdots \cap A_{i_k} \right| 52 | \end{align*} 53 | 54 | \subsubsection{Princípio da casa dos pombos} 55 | 56 | Se $n$ pombos são colocados em $m$ casas, então pelo menos uma casa terá $\lceil \frac{n}{m} \rceil$ pombos ou mais. 57 | -------------------------------------------------------------------------------- /.github/workflows/generate_almanaque_pdf.yml: -------------------------------------------------------------------------------- 1 | name: Gerar Almanaque PDF 2 | 3 | on: 4 | workflow_dispatch: {} 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build_and_commit_pdf: 11 | if: "!contains(github.event.head_commit.message, 'chore: Atualiza o PDF')" 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repo 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Python 3.12 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: 3.12 23 | 24 | - name: Install LaTeX dependencies 25 | run: | 26 | sudo apt update 27 | sudo apt install -y \ 28 | texlive-latex-base \ 29 | texlive-latex-recommended \ 30 | texlive-latex-extra \ 31 | texlive-lang-portuguese \ 32 | texlive-fonts-recommended \ 33 | latexmk \ 34 | lmodern \ 35 | cm-super \ 36 | rubber 37 | 38 | - name: Run PDF generation script 39 | run: python3 ./.github/scripts/pdfer.py 40 | 41 | - name: Create Pull Request com o novo PDF 42 | uses: peter-evans/create-pull-request@v7 43 | with: 44 | commit-message: "chore: Atualiza o PDF" 45 | 46 | title: "chore: Atualiza o PDF" 47 | body: | 48 | Este PR foi aberto automaticamente pelo GitHub Actions. 🤖 49 | 50 | O PDF do Almanaque foi atualizado para refletir as últimas mudanças nos códigos-fonte e/ou arquivos LaTeX. 51 | branch: "chore/gerar-pdf-${{ github.run_number }}" 52 | base: main 53 | delete-branch: true 54 | sign-commits: true 55 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Disjoint-Set-Union/DSU-Rollback-Bipartido/bipartite_rollback_dsu.cpp: -------------------------------------------------------------------------------- 1 | struct BipartiteRollback_DSU { 2 | vector par, sz, c, bip; 3 | int all_bipartite; 4 | stack>> changes; 5 | void build(int n) { 6 | par.assign(n, 0); 7 | iota(par.begin(), par.end(), 0); 8 | sz.assign(n, 1); 9 | c.assign(n, 0); 10 | bip.assign(n, 1); 11 | all_bipartite = true; 12 | changes.emplace(); 13 | } 14 | int find(int a) { return a == par[a] ? a : find(par[a]); } 15 | int color(int a) { return a == par[a] ? c[a] : c[a] ^ color(par[a]); } 16 | bool bipartite(int a) { return bip[find(a)]; } 17 | void checkpoint() { changes.emplace(); } 18 | void change(int &a, int b) { 19 | changes.top().emplace(a, a); 20 | a = b; 21 | } 22 | bool unite(int a, int b) { 23 | bool equal_color = color(a) == color(b); 24 | a = find(a), b = find(b); 25 | if (a == b) { 26 | if (equal_color) { 27 | change(bip[a], 0); 28 | change(all_bipartite, 0); 29 | } 30 | return false; 31 | } 32 | if (sz[a] < sz[b]) swap(a, b); 33 | change(par[b], a); 34 | change(sz[a], sz[a] + sz[b]); 35 | change(bip[a], bip[a] && bip[b]); 36 | change(all_bipartite, all_bipartite && bip[a]); 37 | if (equal_color) change(c[b], 1); 38 | return true; 39 | } 40 | void rollback() { 41 | while (changes.top().size()) { 42 | auto [a, b] = changes.top().top(); 43 | a = b; 44 | changes.top().pop(); 45 | } 46 | changes.pop(); 47 | } 48 | }; -------------------------------------------------------------------------------- /Codigos/Paradigmas/Exponenciação-de-Matriz/README.md: -------------------------------------------------------------------------------- 1 | # [Exponenciação de Matriz](matrix_exp.cpp) 2 | 3 | Otimização para DP de prefixo quando o valor atual está em função dos últimos $K$ valores já calculados. 4 | 5 | * Complexidade de tempo: $\mathcal{O}(k^3 \cdot \log n)$ 6 | 7 | É preciso mapear a DP para uma exponenciação de matriz. 8 | 9 | ### Uso Comum 10 | 11 | DP: 12 | 13 | $$ dp[n] = \sum_{i=1}^{k} c[i] \cdot dp[n - i] $$ 14 | 15 | Mapeamento: 16 | 17 | $$ \begin{pmatrix} 0&1&0&0&...&0 \\\ 0&0&1&0&...&0 \\\ 0&0&0&1&...&0 \\\ ...&...&...&...&...&... \\\ c[k]&c[k-1]&c[k-2]&...&c[1]&0 \end{pmatrix}^n \times \begin{pmatrix} dp[0] \\\ dp[1] \\\ dp[2] \\\ ... \\\ dp[k-1] \end{pmatrix} $$ 18 | 19 | --- 20 | ### Variação que dependa de **constantes** e do **índice** 21 | 22 | Exemplo de DP: 23 | 24 | $$ dp[i] = dp[i-1] + 2 \cdot i^2 + 3 \cdot i + 5 $$ 25 | 26 | Nesses casos é preciso fazer uma linha para manter cada constante e potência do índice. 27 | 28 | Mapeamento: 29 | 30 | $$ \begin{pmatrix} 1&5&3&2 \\\ 0&1&0&0 \\\ 0&1&1&0 \\\ 0&1&2&1 \end{pmatrix}^n \times \begin{pmatrix} dp[0] \\\ 1 \\\ 1 \\\ 1\end {pmatrix} \begin{matrix} \text{mantém } dp[i] \\\ \text{mantém }1 \\\ \text{mantém }i \\\ \text{mantém }i^2 \end {matrix} $$ 31 | 32 | ### Variação Multiplicativa 33 | 34 | Exemplo de DP: 35 | 36 | $$ dp[n] = c \cdot \prod_{i=1}^{k} dp[n-i] $$ 37 | 38 | Nesses casos é preciso trabalhar com o logaritmo e temos o caso padrão: 39 | 40 | 41 | $$ \log(dp[n]) = \log(c) + \sum_{i=1}^{k} \log(dp[n-i]) $$ 42 | 43 | Se a resposta precisar ser inteira, deve-se fatorar a constante e os valores inicias e então fazer uma exponenciação para cada fator primo. Depois é só juntar a resposta no final. 44 | -------------------------------------------------------------------------------- /Codigos/String/Suffix-Array/suffix_array.cpp: -------------------------------------------------------------------------------- 1 | const int MAX = 5e5 + 5; 2 | struct suffix_array { 3 | string s; 4 | int n, sum, r, ra[MAX], sa[MAX], auxra[MAX], auxsa[MAX], c[MAX], lcp[MAX]; 5 | void counting_sort(int k) { 6 | memset(c, 0, sizeof(c)); 7 | for (int i = 0; i < n; i++) c[(i + k < n) ? ra[i + k] : 0]++; 8 | for (int i = sum = 0; i < max(256, n); i++) sum += c[i], c[i] = sum - c[i]; 9 | for (int i = 0; i < n; i++) auxsa[c[sa[i] + k < n ? ra[sa[i] + k] : 0]++] = sa[i]; 10 | for (int i = 0; i < n; i++) sa[i] = auxsa[i]; 11 | } 12 | void build_sa() { 13 | for (int k = 1; k < n; k <<= 1) { 14 | counting_sort(k); 15 | counting_sort(0); 16 | auxra[sa[0]] = r = 0; 17 | for (int i = 1; i < n; i++) 18 | if (ra[sa[i]] == ra[sa[i - 1]] && ra[sa[i] + k] == ra[sa[i - 1] + k]) 19 | auxra[sa[i]] = r; 20 | else auxra[sa[i]] = ++r; 21 | for (int i = 0; i < n; i++) ra[i] = auxra[i]; 22 | if (ra[sa[n - 1]] == n - 1) break; 23 | } 24 | } 25 | void build_lcp() { 26 | for (int i = 0, k = 0; i < n - 1; i++) { 27 | int j = sa[ra[i] - 1]; 28 | while (s[i + k] == s[j + k]) k++; 29 | lcp[ra[i]] = k; 30 | if (k) k--; 31 | } 32 | } 33 | void set_string(string _s) { 34 | s = _s + '$'; 35 | n = s.size(); 36 | for (int i = 0; i < n; i++) ra[i] = s[i], sa[i] = i; 37 | build_sa(); 38 | build_lcp(); 39 | // for (int i = 0; i < n; i++) 40 | // printf("%2d: %s\n", sa[i], s.c_str() + 41 | // sa[i]); 42 | } 43 | int operator[](int i) { return sa[i]; } 44 | } sa; 45 | -------------------------------------------------------------------------------- /Codigos/Grafos/Pontes/Componentes-Aresta-Biconexas/ebcc_components.cpp: -------------------------------------------------------------------------------- 1 | const int N = 3e5 + 5; 2 | int n, m, timer, ncc; 3 | vector adjbcc[N]; 4 | vector adj[N]; 5 | int tin[N], low[N], ebcc[N]; 6 | 7 | void dfs_bridge(int u, int p = -1) { 8 | low[u] = tin[u] = ++timer; 9 | for (int v : adj[u]) { 10 | if (tin[v] != 0 && v != p) { 11 | low[u] = min(low[u], tin[v]); 12 | } else if (v != p) { 13 | dfs_bridge(v, u); 14 | low[u] = min(low[u], low[v]); 15 | } 16 | } 17 | } 18 | 19 | void dfs_ebcc(int u, int p, int cc) { 20 | if (p != -1 && low[u] == tin[u]) { 21 | // edge (u, p) eh uma ponte 22 | cc = ++ncc; 23 | } 24 | ebcc[u] = cc; 25 | for (int v : adj[u]) 26 | if (ebcc[v] == -1) dfs_ebcc(v, u, cc); 27 | } 28 | 29 | void build_ebcc_graph() { 30 | ncc = timer = 0; 31 | for (int i = 0; i < n; i++) { 32 | tin[i] = low[i] = 0; 33 | ebcc[i] = -1; 34 | adjbcc[i].clear(); 35 | } 36 | for (int i = 0; i < n; i++) 37 | if (tin[i] == 0) dfs_bridge(i); 38 | for (int i = 0; i < n; i++) 39 | if (ebcc[i] == -1) dfs_ebcc(i, -1, ncc), ++ncc; 40 | // Opcao 1 - constroi o grafo comprimido passando por todas as edges 41 | for (int u = 0; u < n; u++) { 42 | for (auto v : adj[u]) { 43 | if (ebcc[u] != ebcc[v]) { 44 | adjbcc[ebcc[u]].emplace_back(ebcc[v]); 45 | } else { 46 | // faz algo 47 | } 48 | } 49 | } 50 | // Opcao 2 - constroi o grafo comprimido passando so pelas pontes 51 | // for (auto [u, v] : bridges) { 52 | // adjbcc[ebcc[u]].emplace_back(ebcc[v]); 53 | // adjbcc[ebcc[v]].emplace_back(ebcc[u]); 54 | // } 55 | } -------------------------------------------------------------------------------- /Codigos/Matemática/Inverso-Modular/README.md: -------------------------------------------------------------------------------- 1 | # Inverso Modular 2 | 3 | Algoritmos para calcular o inverso modular de um número. O inverso modular de um inteiro $a$ é outro inteiro $x$ tal que $a \cdot x \equiv 1 \pmod{MOD}$ 4 | 5 | O inverso modular de um inteiro $a$ é outro inteiro $x$ tal que $a * x$ é congruente a $1 \mod MOD$. 6 | 7 | # [Inverso Modular](modular_inverse.cpp) 8 | 9 | Calcula o inverso modular de $a$. 10 | 11 | Utiliza o algoritmo Exp Mod, portanto, espera-se que $MOD$ seja um número primo. 12 | 13 | * Complexidade de tempo: $\mathcal{O}(\log(\text{MOD}))$. 14 | * Complexidade de espaço: $\mathcal{O}(1)$. 15 | 16 | # [Inverso Modular por MDC Estendido](modular_inverse_coprime.cpp) 17 | 18 | Calcula o inverso modular de $a$. 19 | 20 | Utiliza o algoritmo Euclides Extendido, portanto, espera-se que $MOD$ seja coprimo com $a$. 21 | 22 | Retorna $-1$ se essa suposição for quebrada. 23 | 24 | * Complexidade de tempo: $\mathcal{O}(\log(\text{MOD}))$. 25 | * Complexidade de espaço: $\mathcal{O}(1)$. 26 | 27 | # [Inverso Modular para 1 até MAX](modular_inverse_linear.cpp) 28 | 29 | Calcula o inverso modular para todos os números entre $1$ e $MAX$. 30 | 31 | Espera-se que $MOD$ seja primo. 32 | 33 | * Complexidade de tempo: $\mathcal{O}(\text{MAX})$. 34 | * Complexidade de espaço: $\mathcal{O}(\text{MAX})$. 35 | 36 | # [Inverso Modular para todas as potências](modular_inverse_pow.cpp) 37 | 38 | Seja $b$ um número inteiro qualquer. 39 | 40 | Calcula o inverso modular para todas as potências de $b$ entre $b^0$ e $b^MAX$. 41 | 42 | É necessário calcular antecipadamente o inverso modular de $b$, para 2 é sempre $(MOD+1)/2$. 43 | 44 | Espera-se que $MOD$ seja coprimo com $b$. 45 | 46 | * Complexidade de tempo: $\mathcal{O}(\text{MAX})$. 47 | * Complexidade de espaço: $\mathcal{O}(\text{MAX})$. -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/LiChao-Tree/lichao_tree.cpp: -------------------------------------------------------------------------------- 1 | const ll INF = ll(2e18) + 10; 2 | struct Line { 3 | ll a, b; 4 | Line(ll a_ = 0, ll b_ = -INF) : a(a_), b(b_) { } 5 | ll operator()(ll x) { return a * x + b; } 6 | }; 7 | 8 | template 9 | struct LichaoTree { 10 | vector tree; 11 | vector L, R; 12 | 13 | int newnode() { 14 | tree.push_back(Line()); 15 | L.push_back(0); 16 | R.push_back(0); 17 | return int(tree.size()) - 1; 18 | } 19 | 20 | LichaoTree() { 21 | newnode(); 22 | newnode(); 23 | } 24 | 25 | int lc(int p, bool create = false) { 26 | if (create && L[p] == 0) L[p] = newnode(); 27 | return L[p]; 28 | } 29 | 30 | int rc(int p, bool create = false) { 31 | if (create && R[p] == 0) R[p] = newnode(); 32 | return R[p]; 33 | } 34 | 35 | void insert(Line line, int p = 1, ll l = MINL, ll r = MAXR) { 36 | if (p == 0) return; 37 | ll mid = l + (r - l) / 2; 38 | bool bl = line(l) > tree[p](l); 39 | bool bm = line(mid) > tree[p](mid); 40 | bool br = line(r) > tree[p](r); 41 | if (bm) swap(tree[p], line); 42 | if (line.b == -INF) return; 43 | if (bl != bm) insert(line, lc(p, true), l, mid - 1); 44 | else if (br != bm) insert(line, rc(p, true), mid + 1, r); 45 | } 46 | 47 | ll query(int x, int p = 1, ll l = MINL, ll r = MAXR) { 48 | if (p == 0 || tree[p](x) == -INF || (l > r)) return -INF; 49 | if (l == r) return tree[p](x); 50 | ll mid = l + (r - l) / 2; 51 | if (x < mid) return max(tree[p](x), query(x, lc(p), l, mid - 1)); 52 | else return max(tree[p](x), query(x, rc(p), mid + 1, r)); 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /Codigos/String/Hashing/Hashing/hashing.cpp: -------------------------------------------------------------------------------- 1 | const int MOD1 = 998244353; 2 | const int MOD2 = (int)(1e9) + 7; 3 | using mint1 = Mint; 4 | using mint2 = Mint; 5 | 6 | struct Hash { 7 | mint1 h1; 8 | mint2 h2; 9 | Hash(mint1 _h1 = 0, mint2 _h2 = 0) : h1(_h1), h2(_h2) { } 10 | bool operator==(Hash o) const { return h1 == o.h1 && h2 == o.h2; } 11 | bool operator!=(Hash o) const { return h1 != o.h1 || h2 != o.h2; } 12 | bool operator<(Hash o) const { return h1 == o.h1 ? h2 < o.h2 : h1 < o.h1; } 13 | Hash operator+(Hash o) const { return {h1 + o.h1, h2 + o.h2}; } 14 | Hash operator-(Hash o) const { return {h1 - o.h1, h2 - o.h2}; } 15 | Hash operator*(Hash o) const { return {h1 * o.h1, h2 * o.h2}; } 16 | Hash operator/(Hash o) const { return {h1 / o.h1, h2 / o.h2}; } 17 | }; 18 | 19 | const int PRIME = 33333331; // qualquer primo na ordem do alfabeto 20 | const int MAXN = 1e6 + 5; 21 | Hash PR = {PRIME, PRIME}; 22 | Hash invPR = {mint1(1) / PRIME, mint2(1) / PRIME}; 23 | Hash pot[MAXN], invpot[MAXN]; 24 | 25 | void precalc() { 26 | pot[0] = invpot[0] = Hash(1, 1); 27 | for (int i = 1; i < MAXN; i++) { 28 | pot[i] = pot[i - 1] * PR; 29 | invpot[i] = invpot[i - 1] * invPR; 30 | } 31 | } 32 | 33 | struct Hashing { 34 | int N; 35 | vector hsh; 36 | Hashing() { } 37 | Hashing(string s) : N((int)s.size()), hsh(N + 1) { 38 | for (int i = 0; i < N; i++) { 39 | int c = (int)s[i]; 40 | hsh[i + 1] = hsh[i] + (pot[i + 1] * Hash(c, c)); 41 | } 42 | } 43 | Hash operator()(int l = 0, int r = -1) const { 44 | #warning Chamou o precalc()? 45 | // se ja chamou o precalc() pode apagar essa linha de cima 46 | if (r == -1) r = N - 1; 47 | return (hsh[r + 1] - hsh[l]) * invpot[l]; 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Interval-Tree/interval_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace __gnu_pbds; 4 | 5 | struct interval { 6 | long long lo, hi, id; 7 | bool operator<(const interval &i) const { 8 | return tuple(lo, hi, id) < tuple(i.lo, i.hi, i.id); 9 | } 10 | }; 11 | 12 | const long long INF = 1e18; 13 | 14 | template 15 | struct intervals_node_update { 16 | typedef long long metadata_type; 17 | int sz = 0; 18 | virtual CNI node_begin() const = 0; 19 | virtual CNI node_end() const = 0; 20 | inline vector overlaps(const long long l, const long long r) { 21 | queue q; 22 | q.push(node_begin()); 23 | vector vec; 24 | while (!q.empty()) { 25 | CNI it = q.front(); 26 | q.pop(); 27 | if (it == node_end()) continue; 28 | if (r >= (*it)->lo && l <= (*it)->hi) vec.push_back((*it)->id); 29 | CNI l_it = it.get_l_child(); 30 | long long l_max = (l_it == node_end()) ? -INF : l_it.get_metadata(); 31 | if (l_max >= l) q.push(l_it); 32 | if ((*it)->lo <= r) q.push(it.get_r_child()); 33 | } 34 | return vec; 35 | } 36 | inline void operator()(NI it, CNI end_it) { 37 | const long long l_max = 38 | (it.get_l_child() == end_it) ? -INF : it.get_l_child().get_metadata(); 39 | const long long r_max = 40 | (it.get_r_child() == end_it) ? -INF : it.get_r_child().get_metadata(); 41 | const_cast(it.get_metadata()) = max((*it)->hi, max(l_max, r_max)); 42 | } 43 | }; 44 | typedef tree, rb_tree_tag, intervals_node_update> 45 | interval_tree; 46 | -------------------------------------------------------------------------------- /Codigos/Primitivas/Modular-Int/mint.cpp: -------------------------------------------------------------------------------- 1 | template 2 | struct Mint { 3 | using U = long long; 4 | // se o modulo for long long, usar U = __int128 5 | using m = Mint; 6 | T v; 7 | Mint(T val = 0) : v(val) { 8 | assert(sizeof(T) * 2 <= sizeof(U)); 9 | if (v < -MOD || v >= 2 * MOD) v %= MOD; 10 | if (v < 0) v += MOD; 11 | if (v >= MOD) v -= MOD; 12 | } 13 | Mint(U val) : v(T(val % MOD)) { 14 | assert(sizeof(T) * 2 <= sizeof(U)); 15 | if (v < 0) v += MOD; 16 | } 17 | bool operator==(m o) const { return v == o.v; } 18 | bool operator<(m o) const { return v < o.v; } 19 | bool operator!=(m o) const { return v != o.v; } 20 | m pwr(m b, U e) const { 21 | m res = 1; 22 | while (e > 0) { 23 | if (e & 1) res *= b; 24 | b *= b, e /= 2; 25 | } 26 | return res; 27 | } 28 | m &operator+=(m o) { 29 | v -= MOD - o.v; 30 | if (v < 0) v += MOD; 31 | return *this; 32 | } 33 | m &operator-=(m o) { 34 | v -= o.v; 35 | if (v < 0) v += MOD; 36 | return *this; 37 | } 38 | m &operator*=(m o) { 39 | v = (T)((U)v * o.v % MOD); 40 | return *this; 41 | } 42 | m &operator/=(m o) { return *this *= o.pwr(o, MOD - 2); } 43 | m &operator^=(U e) { return *this = pwr(*this, e); } 44 | friend m operator-(m a, m b) { return a -= b; } 45 | friend m operator+(m a, m b) { return a += b; } 46 | friend m operator*(m a, m b) { return a *= b; } 47 | friend m operator/(m a, m b) { return a /= b; } 48 | friend m operator^(m a, U e) { return a.pwr(a, e); } 49 | 50 | m operator-() { return m(this->v ? MOD - this->v : 0); } 51 | m inv() const { return pwr(*this, MOD - 2); } // MOD must be prime 52 | }; 53 | -------------------------------------------------------------------------------- /LaTeX/chapters/01-cpp/pragmas.tex: -------------------------------------------------------------------------------- 1 | \subsection{Pragmas} 2 | 3 | Os pragmas são diretivas para o compilador, que podem ser usadas para otimizar o código. 4 | 5 | Temos os pragmas de otimização, como por exemplo: 6 | 7 | \begin{itemize} 8 | \item \texttt{\#pragma GCC optimize("O2")}: Otimizações de nível 2 (padrão de competições) 9 | \item \texttt{\#pragma GCC optimize("O3")}: Otimizações de nível 3 (seguro para usar) 10 | \item \texttt{\#pragma GCC optimize("Ofast")}: Otimizações agressivas (perigoso!) 11 | \item \texttt{\#pragma GCC optimize("unroll-loops")}: Otimiza os loops mas pode levar a \textit{cache misses} 12 | \end{itemize} 13 | 14 | E também os pragmas de \textit{target}, que são usados para otimizar o código para um certo processador: 15 | 16 | \begin{itemize} 17 | \item \texttt{\#pragma GCC target("avx2")}: Otimiza instruções para processadores com suporte a AVX2 18 | \item \texttt{\#pragma GCC target("sse4")}: Parecido com o de cima, mas mais antigo 19 | \item \texttt{\#pragma GCC target("popcnt")}: Otimiza o \textit{popcount} em processadores que suportam 20 | \item \texttt{\#pragma GCC target("lzcnt")}: Otimiza o \textit{leading zero count} em processadores que suportam 21 | \item \texttt{\#pragma GCC target("bmi")}: Otimiza instruções de \textit{bit manipulation} em processadores que suportam 22 | \item \texttt{\#pragma GCC target("bmi2")}: Mesmo que o de cima, mas mais recente 23 | \end{itemize} 24 | 25 | Em geral, esses pragmas são usados para otimizar o código em competições, mas é importante usá-los com certa sabedoria, em alguns casos eles podem piorar o desempenho do código. 26 | 27 | Uma opção relativamente segura de se usar é a seguinte: 28 | 29 | \begin{lstlisting}[language=C++] 30 | #pragma GCC optimize("O3,unroll-loops") 31 | #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") 32 | \end{lstlisting} 33 | -------------------------------------------------------------------------------- /Codigos/Matemática/XOR-Gauss/README.md: -------------------------------------------------------------------------------- 1 | # [XOR Gauss](xor_gauss.cpp) 2 | 3 | Mantém uma base num espaço vetorial de $L$ dimensões sobre $\mathbb{Z}_2$. Permite adicionar um vetor $v$ à base em $\mathcal{O}(L)$ e verificar se um vetor $v$ é representável pela base em $\mathcal{O}(L)$. 4 | 5 | Em termos mais simples, dados $n$ inteiros, podemos adicionar cada um deles à base e isso nos dará uma base que consegue representar todos os XORs possíveis entre esses inteiros. 6 | 7 | Também acha o k-ésimo menor vetor representável pela base em $\mathcal{O}(L)$, ou o k-ésimo maior vetor representável pela base em $\mathcal{O}(L)$. 8 | 9 | Informações relevantes: 10 | 11 | - $\text{rank}$ de uma base é o número de vetores que ela contém. No código é a variável `R`. 12 | - Uma base consegue criar $2^{\text{rank}}$ vetores diferentes, ou seja, se criarmos uma base com base em um vetor de tamanho $n$, dentre todos os $2^n$ subsets possíveis, existem exatamente $2^{\text{rank}}$ XORs diferentes. 13 | - Se uma base for criada a partir de um vetor de tamanho $n$, cada XOR possível feito por um subset desse vetor pode ser criado de exatamente $2^{n - \text{rank}}$ formas diferentes. 14 | 15 | Os métodos são: 16 | 17 | - `reduce`: recebe um número $x$ (será tratado como um vetor no espaço vetorial) e subtrai os vetores já existentes na base que estão presentes em $x$. Sendo assim, se ao final do `reduce`, $x$ for diferente de zero, ele não é representável por uma combinação linear dos vetores da base, se for zero, ele é representável. 18 | - `insert`: insere um vetor na base, se ele não for representável. No caso, o vetor inserido ao tentar inserir um valor $x$ na base, será o `reduce` de $x$. 19 | - `kth_greatest`: retorna o k-ésimo maior vetor representável pela base. 20 | - `kth_smallest`: retorna o k-ésimo menor vetor não representável pela base. 21 | 22 | Todos os métodos são $\mathcal{O}(L)$. -------------------------------------------------------------------------------- /Codigos/String/Hashing/Hashing-Dinâmico/dynamic_hashing.cpp: -------------------------------------------------------------------------------- 1 | const int MOD1 = 998244353; 2 | const int MOD2 = 1e9 + 7; 3 | using mint1 = Mint; 4 | using mint2 = Mint; 5 | 6 | struct Hash { 7 | mint1 h1; 8 | mint2 h2; 9 | Hash() { } 10 | Hash(mint1 _h1, mint2 _h2) : h1(_h1), h2(_h2) { } 11 | bool operator==(Hash o) const { return h1 == o.h1 && h2 == o.h2; } 12 | bool operator!=(Hash o) const { return h1 != o.h1 || h2 != o.h2; } 13 | bool operator<(Hash o) const { return h1 == o.h1 ? h2 < o.h2 : h1 < o.h1; } 14 | Hash operator+(Hash o) const { return {h1 + o.h1, h2 + o.h2}; } 15 | Hash operator-(Hash o) const { return {h1 - o.h1, h2 - o.h2}; } 16 | Hash operator*(Hash o) const { return {h1 * o.h1, h2 * o.h2}; } 17 | Hash operator/(Hash o) const { return {h1 / o.h1, h2 / o.h2}; } 18 | }; 19 | 20 | const int PRIME = 1001003; // qualquer primo na ordem do alfabeto 21 | const int MAXN = 1e6 + 5; 22 | Hash PR = {PRIME, PRIME}; 23 | Hash invPR = {mint1(1) / PRIME, mint2(1) / PRIME}; 24 | Hash pot[MAXN], invpot[MAXN]; 25 | void precalc() { 26 | pot[0] = invpot[0] = Hash(1, 1); 27 | for (int i = 1; i < MAXN; i++) { 28 | pot[i] = pot[i - 1] * PR; 29 | invpot[i] = invpot[i - 1] * invPR; 30 | } 31 | } 32 | 33 | struct DynamicHashing { 34 | int N; 35 | FenwickTree hsh; 36 | DynamicHashing() { } 37 | DynamicHashing(string s) : N(int(s.size())) { 38 | vector v(N); 39 | for (int i = 0; i < N; i++) { 40 | int c = (int)s[i]; 41 | v[i] = pot[i + 1] * Hash(c, c); 42 | } 43 | hsh = FenwickTree(v); 44 | } 45 | Hash operator()(int l, int r) { return hsh.query(l, r) * invpot[l]; } 46 | void update(int i, char ch) { 47 | int c = (int)ch; 48 | hsh.updateSet(i, pot[i + 1] * Hash(c, c)); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-2D/seg_tree_2d.cpp: -------------------------------------------------------------------------------- 1 | struct SegTree2D { 2 | ll merge(ll a, ll b) { return a + b; } 3 | ll neutral = 0; 4 | int n, m; 5 | vector> t; 6 | void build(int _n, int _m) { 7 | n = _n, m = _m; 8 | t.assign(2 * n, vector(2 * m, neutral)); 9 | for (int i = 2 * n - 1; i >= n; i--) 10 | for (int j = m - 1; j > 0; j--) 11 | t[i][j] = merge(t[i][j << 1], t[i][j << 1 | 1]); 12 | for (int i = n - 1; i > 0; i--) 13 | for (int j = 2 * m - 1; j > 0; j--) 14 | t[i][j] = merge(t[i << 1][j], t[i << 1 | 1][j]); 15 | } 16 | ll inner_query(int idx, int l, int r) { 17 | ll res = neutral; 18 | for (l += m, r += m + 1; l < r; l >>= 1, r >>= 1) { 19 | if (l & 1) res = merge(res, t[idx][l++]); 20 | if (r & 1) res = merge(res, t[idx][--r]); 21 | } 22 | return res; 23 | } 24 | // query do ponto (a, b) ate o ponto (c, d), retorna neutro se a > c ou b > d 25 | ll query(int a, int b, int c, int d) { 26 | ll res = neutral; 27 | for (a += n, c += n + 1; a < c; a >>= 1, c >>= 1) { 28 | if (a & 1) res = merge(res, inner_query(a++, b, d)); 29 | if (c & 1) res = merge(res, inner_query(--c, b, d)); 30 | } 31 | return res; 32 | } 33 | void inner_update(int idx, int i, ll x) { 34 | auto &c = t[idx]; 35 | i += m; 36 | c[i] = x; 37 | for (i >>= 1; i > 0; i >>= 1) c[i] = merge(c[i << 1], c[i << 1 | 1]); 38 | } 39 | void update(int i, int j, ll x) { 40 | i += n; 41 | inner_update(i, j, x); 42 | for (i >>= 1; i > 0; i >>= 1) { 43 | ll val = merge(t[i << 1][j + m], t[i << 1 | 1][j + m]); 44 | inner_update(i, j, val); 45 | } 46 | } 47 | } seg; 48 | -------------------------------------------------------------------------------- /Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Esparsa/seg_tree_sparse.cpp: -------------------------------------------------------------------------------- 1 | const ll MINL = (ll)-1e9 - 5, MAXR = (ll)1e9 + 5; 2 | struct SegTree { 3 | ll merge(ll a, ll b) { return a + b; } 4 | const ll neutral = 0; 5 | vector t; 6 | vector Lc, Rc; 7 | inline int newnode() { 8 | t.push_back(neutral); 9 | Lc.push_back(0); 10 | Rc.push_back(0); 11 | return (int)t.size() - 1; 12 | } 13 | inline int lc(int p, bool create = false) { 14 | if (create && Lc[p] == 0) Lc[p] = newnode(); 15 | return Lc[p]; 16 | } 17 | inline int rc(int p, bool create = false) { 18 | if (create && Rc[p] == 0) Rc[p] = newnode(); 19 | return Rc[p]; 20 | } 21 | SegTree() { 22 | newnode(); 23 | newnode(); 24 | } 25 | ll query(int p, ll l, ll r, ll L, ll R) { 26 | if (p == 0 || l > R || r < L) return neutral; 27 | if (l >= L && r <= R) return t[p]; 28 | ll mid = l + (r - l) / 2; 29 | auto ql = query(lc(p), l, mid, L, R); 30 | auto qr = query(rc(p), mid + 1, r, L, R); 31 | return merge(ql, qr); 32 | } 33 | ll query(ll l, ll r) { return query(1, MINL, MAXR, l, r); } 34 | void update(int p, ll l, ll r, ll i, ll x, bool repl) { 35 | if (p == 0) return; 36 | if (l == r) { 37 | if (repl) t[p] = x; // substitui 38 | else t[p] += x; // soma 39 | return; 40 | } 41 | ll mid = l + (r - l) / 2; 42 | if (i <= mid) update(lc(p, true), l, mid, i, x, repl); 43 | else update(rc(p, true), mid + 1, r, i, x, repl); 44 | t[p] = merge(t[lc(p)], t[rc(p)]); 45 | } 46 | void update(ll i, ll x, bool repl) { update(1, MINL, MAXR, i, x, repl); } 47 | void sumUpdate(ll i, ll x) { update(i, x, 0); } 48 | void setUpdate(ll i, ll x) { update(i, x, 1); } 49 | } seg; 50 | --------------------------------------------------------------------------------