Você está na página 1de 69

Macacário Maratona de Programação v2.

0
Instituto Tecnológico de Aeronáutica

Lucas França de Oliveira (Mexicano T-18)

9 de agosto de 2017
Sumário

1 Introdução 4
1.1 Bugs do Milênio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Recomendações gerais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Os 1010 mandamentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Limites da representação de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.5 Quantidade de números primos de 1 até 10n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.6 Triângulo de Pascal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.7 Fatoriais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.8 Tabela ASCII . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.9 Primos até 10.000 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2 C++ e Biblioteca STD 10


2.1 Complex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2 Pair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4 Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.5 Deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.6 Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.7 Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.8 Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.9 Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.10 Priority Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.11 Bitset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.12 Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3 Estruturas de dados 12
3.1 Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2 Union-Find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3 Binary Indexed Tree / Fenwick Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.4 Binary Indexed Tree / Fenwick Tree com range updates e queries . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.5 Segment Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.6 Segment Tree com Lazy Propagation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.7 2D Binary Indexed Tree / Fenwick Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.8 2D Segment Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.9 Treap / Cartesian Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.10 Treap / Cartesian Tree implícita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.11 Link Cut Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.12 Link Cut Tree não direcionada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.13 Splay Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.14 AVL Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.15 Heavy-Light Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.16 Centroid Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3.17 Convex Hull Trick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.18 Lowest Commom Ancestor (LCA) e distância na árvore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.19 Merge Sort Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.20 Sparse Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.21 Código de Huffman . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

1
SUMÁRIO 2

4 Paradigmas 26
4.1 Merge Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 Quick Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.3 Longest Increasing Subsequence (LIS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.4 Maximum Sum Increasing Subsequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.5 Problema dos Pares mais Próximos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.6 Otimização de Dois Ponteiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.7 Otimização de Convex Hull Trick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.8 Otimização de Slope Trick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.9 Otimização de Divisão e Conquista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.10 Otimização de Knuth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

5 Grafos 30
5.1 DFS e BFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.2 DFS Spanning Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.3 Pontos de articulação e Pontes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.4 Ordenação Topológica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.5 Componentes Fortemente Conexos: Algoritmo de Tarjan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.6 Componentes Fortemente Conexos: Algoritmo de Kosaraju . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.7 Caminho mínimo: Algoritmo de Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.8 Caminho mínimo: Algoritmo de Floyd-Warshall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.9 Caminho mínimo: Algoritmo de Bellman-Ford . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.10 Caminho mínimo: Shortest Path Faster Algorithm (SPFA) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.11 Árvore Geradora Mínima: Algoritmo de Kruskal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.12 Árvore Geradora Mínima: Algoritmo de Prim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.13 2-SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.14 Fluxo Máximo: Algoritmo de Edmonds-Karp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.15 Fluxo Máximo: Algoritmo de Dinic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.16 Maximum Matching: Algoritmo húngaro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.17 Maximum Matching: Algoritmo de Hopcroft-Karp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5.18 Maximum Matching: Algoritmo Blossom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.19 Corte Mínimo Global: Algoritmo de Stoer-Wagner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.20 Min Cost Max Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.21 Euler Tour: Algoritmo de Fleury . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.22 Dominator Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
5.23 Grafos notáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

6 Matemática 41
6.1 Aritmética Modular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.2 Números primos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.3 Fórmula de Legendre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.4 Números de Catalan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.5 Algoritmo de Pollard-Rho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.6 Baby-Step Giant-Step para Logaritmo Discreto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.7 Código de Gray . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.8 Teorema Chinês dos Restos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.9 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.10 Exponenciação de matrizes e Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.11 Sistemas Lineares: Determinante e Eliminação de Gauss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.12 Multiplicação de matriz esparsa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.13 Método de Gauss-Seidel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.14 Eliminação de Gauss com o XOR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.15 Fast Fourier Transform (FFT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.16 Number Theoretic Transform (NTT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.17 Convolução circular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.18 Triplas Pitagóricas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.19 Algoritmo de Floyd . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.20 Bignum em C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
SUMÁRIO 3

6.21 BigInteger em Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50


6.22 Jogo de Nim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50

7 Processamento de Strings 51
7.1 Knuth-Morris-Pratt (KMP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.2 Rabin-Karp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.3 Repetend: menor período de uma string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.4 Suffix Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.5 Suffix Array: string matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.6 Suffix Array: Longest Common Prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.7 Suffix Array: Longest Repeated Substring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.8 Suffix Array: Longest Common Substring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.9 Longest Palindromic Substring: Algoritmo de Manacher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
7.10 Aho Corasick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
7.11 Longest Common Subsequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
7.12 Função Z e Algoritmo Z . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55

8 Geometria Computacional 56
8.1 Ponto 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.2 Linha 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.3 Círculo 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.4 Triângulo 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
8.5 Polígono 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
8.6 Convex Hull . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.7 Ponto dentro de polígono convexo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.8 Soma de Minkowski . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.9 Minimum Enclosing Circle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.10 Ponto inteiro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.11 Ponto 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.12 Triângulo 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.13 Linha 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.14 Grande Círculo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
8.15 Coordenadas polares, cilíndricas e esféricas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
8.16 Cálculo Vetorial 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
8.17 Cálculo Vetorial 3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
8.18 Geometria Analítica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
8.19 Ponto ótimo numa linha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64

9 Miscelânea 65
9.1 Algoritmo de Mo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.2 Algoritmo de Mo sem remoção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.3 Iteração sobre polyominos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.4 Quadrádo Mágico Ímpar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.5 Expressão Parentética para Polonesa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.6 Problema do histograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.7 Problema do casamento estável . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
9.8 Teoremas e Fórmulas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Capítulo 1

Introdução

1.1 Bugs do Milênio


Erros teóricos: • Declarar variável global e variável local com mesmo
nome (é pedir pra dar merda...).
• Não ler o enunciado do problema com calma.
Erros de implementação:
• Assumir algum fato sobre a solução na pressa.
• Não reler os limites do problema antes de submeter. • Definir variável com tipo errado (int por double, int por
char).
• Quando adaptar um algoritmo, atentar para todos os
detalhes da estrutura do algoritmo, se devem (ou não) • Não usar variável com nome max e min.
ser modificados (ex:marcação de vértices/estados). • Não esquecer que .size() é unsigned.
• O problema pode ser NP, disfarçado ou mesmo sem limi- • Lembrar que 1 é int, ou seja, se fizer long long a =
tes especificados. Nesse caso a solução é bronca mesmo. 1 << 40;, não irá funcionar (o ideal é fazer
Não é hora de tentar ganhar o prêmio nobel. long long a = 1LL << 40;).
Erros com valor máximo de variável: Erros em limites:

• Verificar com calma (fazer as contas direito) para ver se • Qual o ordem do tempo e memória? 108 é uma referên-
o infinito é tão infinito quanto parece. cia para tempo. Sempre verificar rapidamente a memó-
ria, apesar de que o limite costuma ser bem grande.
• Verificar se operações com infinito estouram 31 bits.
• A constante pode ser muito diminuída com um algo-
• Usar multiplicacao de int’s e estourar 32 bits (por exem-
ritmo melhor (ex: húngaro no lugar de fluxo) ou com
plo, checar sinais usando a ∗ b > 0).
operações mais rápidas (ex: divisões são lentas, bitwise
Erros de casos extremos: é rápido)?
• O exercício é um caso particular que pode (e está pre-
• Testou caso n = 0? n = 1? n = M AXN ? Muitas vezes
cisando) ser otimizado e não usar direto a biblioteca?
tem que tratar separado.
• Pense em todos os casos que podem ser considerados Erros em doubles:
casos extremos ou casos isolados. • Primeiro, evitar (a não ser que seja necessário ou mais
• Casos extremos podem atrapalhar não só no algoritmo, simples a solução) usar f loat/double. E.g. conta que só
mas em coisas como construir alguma estrutura (ex: precisa de 2 casas decimais pode ser feita com inteiro e
lista de adj em grafos). depois %100.
• Não esquecer de self-loops ou multiarestas em grafos. • Sempre usar double, não f loat (a não ser que o enunci-
• Em problemas de caminho Euleriano, verificar se o grafo ado peça explicitamente).
é conexo. • Testar igualdade com tolerância (absoluta, e talvez re-
lativa).
Erros de desatenção em implementação:
• Cuidado com erros de imprecisão, em particular evitar
• Errar ctrl-C/ctrl-V em código. Muito comum. ao máximo subtrair dois números praticamente iguais.
• Colocar igualdade dentro de if ? (if (a = 0)continue;) Outros erros:
• Esquecer de inicializar variável. • Evitar (a não ser que seja necessário) alocação dinâmica
• Trocar break por continue (ou vice-versa). de memória.

4
CAPÍTULO 1. INTRODUÇÃO 5

• Não usar STL desnecessariamente (ex: vector quando rou variável que soma algo? zerou com zero? era pra
um array normal dá na mesma), mas usar se facili- zerar com zero, com -1 ou com INF?).
tar (ex: nomes associados a vértices de um grafo - • Saída está formatada corretamente?
map < string, int >) ou se precisar (ex: um algoritmo
O(nlogn) que usa < set > é necessário para passar no • Declarou vetor com tamanho suficiente?
tempo). • Cuidado ao tirar o módulo de número negativo. Ex.:
x%n não dá o resultado esperado se x é negativo, fazer
• Não inicializar variável a cada teste (zerou vetores? ze- (x%n + n)%n.

1.2 Recomendações gerais


Cortesia da PUC-RJ.

ANTES DA PROVA
• Revisar os algoritmos disponíveis na biblioteca.
• Revisar a referência STL.
• Reler este roteiro.
• Ouvir o discurso motivacional do técnico.
ANTES DE IMPLEMENTAR UM PROBLEMA

• Quem for implementar deve relê-lo antes.


• Peça todas as clarifications que forem necessárias.
• Marque as restrições e faça contas com os limites da entrada.
• Teste o algoritmo no papel e convença outra pessoa de que ele funciona.
• Planeje a resolução para os problemas grandes: a equipe se junta para definir as estruturas de dados, mas cada pessoa
escreve uma função.
DEBUGAR UM PROGRAMA
• Ao encontrar um bug, escreva um caso de teste que o dispare.
• Reimplementar trechos de programas entendidos errados.
• Em caso de RE, procure todos os [, / e %.

1.3 Os 1010 mandamentos


Também cortesia da PUC-RJ.

0. Não dividirás por zero.


1. Não alocarás dinamicamente.
2. Compararás números de ponto flutuante usando EPS.
3. Verificarás se o grafo pode ser desconexo.
4. Verificarás se as arestas do grafo podem ter peso negativo.
5. Verificarás se pode haver mais de uma aresta ligando dois vértices.
6. Conferirás todos os índices de uma programação dinâmica.
7. Reduzirás o branching factor da DFS.
8. Farás todos os cortes possíveis em uma DFS.
9. Tomarás cuidado com pontos coincidentes e com pontos colineares.
CAPÍTULO 1. INTRODUÇÃO 6

1.4 Limites da representação de dados

tipo bits mínimo .. máximo precisão decimal


char 8 0 .. 127 2
signed char 8 −128 .. 127 2
unsigned char 8 0 .. 255 2
short 16 −32.768 .. 32.767 4
unsigned short 16 0 .. 65.535 4
int 32 −2 × 109 .. 2 × 109 9
unsigned int 32 0 .. 4 × 109 9
long long 64 −9 × 1018 .. 9 × 1018 18
unsigned long long 64 0 .. 18 × 1018 19

tipo bits expoente precisão decimal


float 32 38 6
double 64 308 15
long double 80 19.728 18

1.5 Quantidade de números primos de 1 até 10n


É sempre verdade que n/ln(n) < pi(n) < 1.26 ∗ n/ln(n).

pi(101 ) = 4 pi(102 ) = 25 pi(103 ) = 168


pi(104 ) = 1.229 pi(105 ) = 9.592 pi(106 ) = 78.498
pi(107 ) = 664.579 pi(108 ) = 5.761.455 pi(109 ) = 50.847.534

1.6 Triângulo de Pascal

n\p 0 1 2 3 4 5 6 7 8 9 10
0 1
1 1 1
2 1 2 1
3 1 3 3 1
4 1 4 6 4 1
5 1 5 10 10 5 1
6 1 6 15 20 15 6 1
7 1 7 21 35 35 21 7 1
8 1 8 28 56 70 56 28 8 1
9 1 9 36 84 126 126 84 36 9 1
10 1 10 45 120 210 252 210 120 45 10 1

C(33, 16) 1.166.803.110 limite do int


C(34, 17) 2.333.606.220 limite do unsigned int
C(66, 33) 7.219.428.434.016.265.740 limite do long long
C(67, 33) 14.226.520.737.620.288.370 limite do unsigned long long
CAPÍTULO 1. INTRODUÇÃO 7

1.7 Fatoriais
Fatoriais até 20 com os limites de tipo.

0! 1
1! 1
2! 2
3! 6
4! 24
5! 120
6! 720
7! 5.040
8! 40.320
9! 362.880
10! 3.628.800
11! 39.916.800
12! 479.001.600 limite do unsigned int
13! 6.227.020.800
14! 87.178.291.200
15! 1.307.674.368.000
16! 20.922.789.888.000
17! 355.687.428.096.000
18! 6.402.373.705.728.000
19! 121.645.100.408.832.000
20! 2.432.902.008.176.640.000 limite do unsigned long long

1.8 Tabela ASCII


CAPÍTULO 1. INTRODUÇÃO 8

1.9 Primos até 10.000


Existem 1.229 números primos até 10.000.

2 3 5 7 11 13 17 19 23 29 31
37 41 43 47 53 59 61 67 71 73 79
83 89 97 101 103 107 109 113 127 131 137
139 149 151 157 163 167 173 179 181 191 193
197 199 211 223 227 229 233 239 241 251 257
263 269 271 277 281 283 293 307 311 313 317
331 337 347 349 353 359 367 373 379 383 389
397 401 409 419 421 431 433 439 443 449 457
461 463 467 479 487 491 499 503 509 521 523
541 547 557 563 569 571 577 587 593 599 601
607 613 617 619 631 641 643 647 653 659 661
673 677 683 691 701 709 719 727 733 739 743
751 757 761 769 773 787 797 809 811 821 823
827 829 839 853 857 859 863 877 881 883 887
907 911 919 929 937 941 947 953 967 971 977
983 991 997 1009 1013 1019 1021 1031 1033 1039 1049
1051 1061 1063 1069 1087 1091 1093 1097 1103 1109 1117
1123 1129 1151 1153 1163 1171 1181 1187 1193 1201 1213
1217 1223 1229 1231 1237 1249 1259 1277 1279 1283 1289
1291 1297 1301 1303 1307 1319 1321 1327 1361 1367 1373
1381 1399 1409 1423 1427 1429 1433 1439 1447 1451 1453
1459 1471 1481 1483 1487 1489 1493 1499 1511 1523 1531
1543 1549 1553 1559 1567 1571 1579 1583 1597 1601 1607
1609 1613 1619 1621 1627 1637 1657 1663 1667 1669 1693
1697 1699 1709 1721 1723 1733 1741 1747 1753 1759 1777
1783 1787 1789 1801 1811 1823 1831 1847 1861 1867 1871
1873 1877 1879 1889 1901 1907 1913 1931 1933 1949 1951
1973 1979 1987 1993 1997 1999 2003 2011 2017 2027 2029
2039 2053 2063 2069 2081 2083 2087 2089 2099 2111 2113
2129 2131 2137 2141 2143 2153 2161 2179 2203 2207 2213
2221 2237 2239 2243 2251 2267 2269 2273 2281 2287 2293
2297 2309 2311 2333 2339 2341 2347 2351 2357 2371 2377
2381 2383 2389 2393 2399 2411 2417 2423 2437 2441 2447
2459 2467 2473 2477 2503 2521 2531 2539 2543 2549 2551
2557 2579 2591 2593 2609 2617 2621 2633 2647 2657 2659
2663 2671 2677 2683 2687 2689 2693 2699 2707 2711 2713
2719 2729 2731 2741 2749 2753 2767 2777 2789 2791 2797
2801 2803 2819 2833 2837 2843 2851 2857 2861 2879 2887
2897 2903 2909 2917 2927 2939 2953 2957 2963 2969 2971
2999 3001 3011 3019 3023 3037 3041 3049 3061 3067 3079
3083 3089 3109 3119 3121 3137 3163 3167 3169 3181 3187
3191 3203 3209 3217 3221 3229 3251 3253 3257 3259 3271
3299 3301 3307 3313 3319 3323 3329 3331 3343 3347 3359
3361 3371 3373 3389 3391 3407 3413 3433 3449 3457 3461
3463 3467 3469 3491 3499 3511 3517 3527 3529 3533 3539
3541 3547 3557 3559 3571 3581 3583 3593 3607 3613 3617
3623 3631 3637 3643 3659 3671 3673 3677 3691 3697 3701
3709 3719 3727 3733 3739 3761 3767 3769 3779 3793 3797
3803 3821 3823 3833 3847 3851 3853 3863 3877 3881 3889
3907 3911 3917 3919 3923 3929 3931 3943 3947 3967 3989
4001 4003 4007 4013 4019 4021 4027 4049 4051 4057 4073
4079 4091 4093 4099 4111 4127 4129 4133 4139 4153 4157
CAPÍTULO 1. INTRODUÇÃO 9

4159 4177 4201 4211 4217 4219 4229 4231 4241 4243 4253
4259 4261 4271 4273 4283 4289 4297 4327 4337 4339 4349
4357 4363 4373 4391 4397 4409 4421 4423 4441 4447 4451
4457 4463 4481 4483 4493 4507 4513 4517 4519 4523 4547
4549 4561 4567 4583 4591 4597 4603 4621 4637 4639 4643
4649 4651 4657 4663 4673 4679 4691 4703 4721 4723 4729
4733 4751 4759 4783 4787 4789 4793 4799 4801 4813 4817
4831 4861 4871 4877 4889 4903 4909 4919 4931 4933 4937
4943 4951 4957 4967 4969 4973 4987 4993 4999 5003 5009
5011 5021 5023 5039 5051 5059 5077 5081 5087 5099 5101
5107 5113 5119 5147 5153 5167 5171 5179 5189 5197 5209
5227 5231 5233 5237 5261 5273 5279 5281 5297 5303 5309
5323 5333 5347 5351 5381 5387 5393 5399 5407 5413 5417
5419 5431 5437 5441 5443 5449 5471 5477 5479 5483 5501
5503 5507 5519 5521 5527 5531 5557 5563 5569 5573 5581
5591 5623 5639 5641 5647 5651 5653 5657 5659 5669 5683
5689 5693 5701 5711 5717 5737 5741 5743 5749 5779 5783
5791 5801 5807 5813 5821 5827 5839 5843 5849 5851 5857
5861 5867 5869 5879 5881 5897 5903 5923 5927 5939 5953
5981 5987 6007 6011 6029 6037 6043 6047 6053 6067 6073
6079 6089 6091 6101 6113 6121 6131 6133 6143 6151 6163
6173 6197 6199 6203 6211 6217 6221 6229 6247 6257 6263
6269 6271 6277 6287 6299 6301 6311 6317 6323 6329 6337
6343 6353 6359 6361 6367 6373 6379 6389 6397 6421 6427
6449 6451 6469 6473 6481 6491 6521 6529 6547 6551 6553
6563 6569 6571 6577 6581 6599 6607 6619 6637 6653 6659
6661 6673 6679 6689 6691 6701 6703 6709 6719 6733 6737
6761 6763 6779 6781 6791 6793 6803 6823 6827 6829 6833
6841 6857 6863 6869 6871 6883 6899 6907 6911 6917 6947
6949 6959 6961 6967 6971 6977 6983 6991 6997 7001 7013
7019 7027 7039 7043 7057 7069 7079 7103 7109 7121 7127
7129 7151 7159 7177 7187 7193 7207 7211 7213 7219 7229
7237 7243 7247 7253 7283 7297 7307 7309 7321 7331 7333
7349 7351 7369 7393 7411 7417 7433 7451 7457 7459 7477
7481 7487 7489 7499 7507 7517 7523 7529 7537 7541 7547
7549 7559 7561 7573 7577 7583 7589 7591 7603 7607 7621
7639 7643 7649 7669 7673 7681 7687 7691 7699 7703 7717
7723 7727 7741 7753 7757 7759 7789 7793 7817 7823 7829
7841 7853 7867 7873 7877 7879 7883 7901 7907 7919 7927
7933 7937 7949 7951 7963 7993 8009 8011 8017 8039 8053
8059 8069 8081 8087 8089 8093 8101 8111 8117 8123 8147
8161 8167 8171 8179 8191 8209 8219 8221 8231 8233 8237
8243 8263 8269 8273 8287 8291 8293 8297 8311 8317 8329
8353 8363 8369 8377 8387 8389 8419 8423 8429 8431 8443
8447 8461 8467 8501 8513 8521 8527 8537 8539 8543 8563
8573 8581 8597 8599 8609 8623 8627 8629 8641 8647 8663
8669 8677 8681 8689 8693 8699 8707 8713 8719 8731 8737
8741 8747 8753 8761 8779 8783 8803 8807 8819 8821 8831
8837 8839 8849 8861 8863 8867 8887 8893 8923 8929 8933
8941 8951 8963 8969 8971 8999 9001 9007 9011 9013 9029
9041 9043 9049 9059 9067 9091 9103 9109 9127 9133 9137
9151 9157 9161 9173 9181 9187 9199 9203 9209 9221 9227
9239 9241 9257 9277 9281 9283 9293 9311 9319 9323 9337
9341 9343 9349 9371 9377 9391 9397 9403 9413 9419 9421
9431 9433 9437 9439 9461 9463 9467 9473 9479 9491 9497
9511 9521 9533 9539 9547 9551 9587 9601 9613 9619 9623
9629 9631 9643 9649 9661 9677 9679 9689 9697 9719 9721
9733 9739 9743 9749 9767 9769 9781 9787 9791 9803 9811
9817 9829 9833 9839 9851 9857 9859 9871 9883 9887 9901
9907 9923 9929 9931 9941 9949 9967 9973
Capítulo 2

C++ e Biblioteca STD

2.1 Complex 2.4 Vector


Exemplo: #include <complex>, complex<double> #include <vector>
point; vector<tipo> V;
Funções: real, imag, abs, arg, norm, conj, polar
Membros de vector:
begin, end, rbegin, rend, size, empty, clear, swap.
2.2 Pair reserve //Seta a capacidade mínima do vetor.
front //Retorna a referência para o primeiro elemento.
#include <utility> back //Retorna a referência para o último elemento.
pair<tipo1, tipo2> P; erase //Remove um elemento do vetor.
tipo1 first, tipo2 second pop_back //Remove o último elemento do vetor.
push_back //Adiciona um elemento no final do vetor.
swap //Troca dois vector’s em O(1).
2.3 List
list<Elem> c //Cria uma lista vazia. 2.5 Deque
list<Elem> c1(c2) //Cria uma cópia de uma outra lista
do mesmo tipo (todos os elementos são copiados). #include <queue>
list<Elem> c(n) //Cria uma lista com n elementos defini- deque<tipo> Q;
dos pelo construtor default. Q[50] //Acesso randômico.
list<Elem> c(n,elem) //Cria uma lista inicializada com
n cópias do elemento elem. Membros de deque:
list<Elem> c(beg,end) //Cria uma lista com os elementos begin, end, rbegin, rend, size, empty, clear, swap.
no intervalo [beg, end). front //Retorna uma referência para o primeiro elemento.
c.l̃ist<Elem>() //Destrói todos os elementos e libera a back //retorna uma referência para o último elemento.
memória. erase //Remove um elemento do deque.
pop_back //Remove o último elemento do deque.
Membros de list: pop_front //Remove o primeiro elemento do deque.
begin, end, rbegin, rend, size, empty, clear, swap. push_back //Insere um elemento no final do deque.
front //Retorna o primeiro elemento. push_front//Insere um elemento no começo do deque.
back //Retorna o último elemento.
push_back //Coloca uma cópia de elem no final da lista.
pop_back //Remove o último elemento e não retorna ele.
push_front//Insere uma cópia de elem no começo da lista. 2.6 Queue
pop_front //Remove o primeiro elemento da lista e não re-
torna ele. #include <queue>
swap //Troca duas list’s em O(1). queue<tipo> Q;
erase (it)//Remove o elemento na posição apontada pelo
iterador it e retorna a posição do próximo elemento. Membros de queue:
erase (beg,end)//Remove todos os elementos no range back //Retorna uma referência ao último elemento da fila.
[beg, end) e retorna a posição do próximo elemento; empty //Retorna se a fila está vazia ou não.
insert (it, pos)//Insere o elemento pos na posição anterior front //Retorna uma referência ao primeiro elemento da fila.
à apontada pelo iterador it. pop //Retorna o primeiro elemento da fila.

10
CAPÍTULO 2. C++ E BIBLIOTECA STD 11

push //Insere um elemento no final da fila. Criando set com comparador personalizado: Utilizar
size //Retorna o número de elementos da fila. struct cmp com bool operator()(tipo, tipo) const e
declarar set<tipo, vector<tipo>, cmp()> S. Cuidado
pra diferenciar os elementos!
2.7 Stack
#include <stack> 2.10 Priority Queue
stack<tipo> P;
#include <queue>
Membros de stack: priority_queue<tipo> pq
empty //Retorna se pilha está vazia ou não.
pop //Remove o elemento no topo da pilha. Membros: empty, size, top, push, pop.
push //Insere um elemento na pilha. Utilizar struct cmp com bool operator ()(tipo,
size //retorna o tamanho da pilha. tipo) e declarar priority_queue<tipo, vector<tipo>,
top //Retorna uma referÊncia para o elemento no topo da cmp()> pq
pilha. .
Maior vem antes!

2.8 Map 2.11 Bitset


#include <map>
#include <bitset>
#include <string>
bitset<MAXN> bs
map<string, int> si;
Membros: empty, size, count, to_string, to_ulong,
Membros de map: to_ullong.
begin, end, rbegin, rend, size, empty, clear, swap, set //Seta todos os elementos para 1.
count. reset //Seta todos os elementos para 0.
erase //Remove um elemento do mapa. flip(n) //Alterna o bit n.
find //retorna um iterador para um elemento do mapa que flip //Alterna todos os bits.
tenha a chave.
lower_bound //Retorna um iterador para o primeiro ele-
mento maior que a chave ou igual à chave. 2.12 Algorithm
upper_bound //Retorna um iterador para o primeiro ele-
mento maior que a chave. #include <algorithm>
int a = max(5,13); //Retorna o maior valor (templati-
Map é um set de pair, ao iterar pelos elementos de map, zado).
i− > f irst é a chave e i− > second é o valor. int a = min(5,13); //Retorna o menor valor.
Map com comparador personalizado: Utilizar struct com vector <int> v;
bool operator<( tipoStruct s ) const . Cuidado pra sort(v.begin(), v.end()); //Ordena de acordo com o ope-
diferenciar os elementos! rador <.
int vv[MAXN];
stable_sort(&vv[0], &vv[MAXN]); //Ordena mantendo
2.9 Set a ordem de elementos iguais.
reverse(v.begin(), v.end()); //Inverte a ordem.
#include <set>
set<tipo> S; Nas funções abaixo pode-se mandar uma função de com-
paração comp customizada mandando &comp como último
Membros de set: parâmetro.
begin, end, rbegin, rend, size, empty, clear, swap. next_permutation(v.begin(), v.end()); //Reordena v
erase //Remove um elemento do set. para a próxima permutação segundo a ordenação lexicográ-
find //Retorna um iterador para um elemento do set. fica. O(n). Retorna f alse se não existir.
insert //Insere um elemento no set. prev_permutation(v.begin(), v.end()); //Reordena v
lower_bound //Retorna um iterador para o primeiro ele- para a permutação anterior segundo a ordenação lexicográ-
mento maior que um valor ou igual a um valor. fica. O(n). Retorna f alse se não existir.
upper_bound //Retorna um iterador para o primeiro ele- nth_element(v.begin(), v.begin()+n, v.end()); //Co-
mento maior que um valor. loca o n-ésimo elemento na posição correta, todos os menores
que ele antes e todos os maiores depois. Expected O(n).
Capítulo 3

Estruturas de dados

3.1 Heap
Árvore de prioridade ou priority_queue. Suporta o update e ordena pelo menor dist[u]. Comparador equivale a ’menor que’.
O vetor heap é 1-indexed.

#define swap ( a , b ) { i n t _x = a ; a=b ; b=_x ; } k >>= 1 ;


#define MAXN 100009 }
e l s e break ;
i n t d i s t [MAXN] ; }
bool comp ( i n t a , i n t b ) { }
return d i s t [ a ] < d i s t [ b ] ; public :
} Heap ( ) { h e a p s i z e = 0 ; }
void c l e a r ( ) { h e a p s i z e = 0 ; }
c l a s s Heap{ bool empty ( ) { return h e a p s i z e ==0; }
private : void update ( i n t n ) {
i n t heap [MAXN] ; i f ( i n v [ n]> h e a p s i z e ) return ;
i n t i n v [MAXN] ; s i f u p ( inv [ n ] ) ;
int h e a p s i z e ; sifdown ( inv [ n ] ) ;
void s i f u p ( i n t n ) { }
i n t k = n << 1 ; void push ( i n t n ) {
while ( k <= h e a p s i z e ) { heap[++ h e a p s i z e ] = n ;
i f ( k < h e a p s i z e && comp ( heap [ k + 1 ] , heap [ k inv [ n ] = heapsize ;
] ) ) k++; sifdown ( heapsize ) ;
i f ( comp ( heap [ k ] , heap [ n ] ) ) { }
swap ( heap [ n ] , heap [ k ] ) ; bool count ( i n t n ) {
i n v [ heap [ n ] ] = n ; int k = inv [ n ] ;
n = i n v [ heap [ k ] ] = k ; return k <= h e a p s i z e && heap [ k ] == n ;
k <<= 1 ; }
} i n t top ( ) {
e l s e break ; i f ( h e a p s i z e <=0) return −1;
} return heap [ 1 ] ;
} }
void s i f d o w n ( i n t n ) { void pop ( ) {
i n t k = n >> 1 ; i f ( h e a p s i z e <=0) return ;
while ( k ) { heap [ 1 ] = heap [ h e a p s i z e − −];
i f ( comp ( heap [ n ] , heap [ k ] ) ) { i n v [ heap [ 1 ] ] = 1 ;
swap ( heap [ n ] , heap [ k ] ) ; sifup (1) ;
i n v [ heap [ n ] ] = n ; }
n = i n v [ heap [ k ] ] = k ; };

12
CAPÍTULO 3. ESTRUTURAS DE DADOS 13

3.2 Union-Find
Disjoint sets em tempo O(logn)

#include <c s t d i o > return i ;


#include <v e c t o r > }
using namespace s t d ; bool i s S a m e S e t ( i n t i , i n t j ) {
return f i n d ( i ) == f i n d ( j ) ;
c l a s s UnionFind { }
private : void u n i o n S e t ( i n t i , i n t j ) {
v e c t o r <int> p a r e n t , rank ; i f ( i s S a m e S e t ( i , j ) ) return ;
public : int x = f i n d ( i ) , y = f i n d ( j ) ;
UnionFind ( i n t N) { i f ( rank [ x ] > rank [ y ] ) p a r e n t [ y ] = x ;
rank . a s s i g n (N+1 , 0 ) ; else {
p a r e n t . a s s i g n (N+1 , 0 ) ; parent [ x ] = y ;
f o r ( i n t i = 0 ; i <= N; i ++) p a r e n t [ i ] = i ; i f ( rank [ x ] == rank [ y ] ) rank [ y]++;
} }
int f i n d ( int i ) { }
while ( i != p a r e n t [ i ] ) i = p a r e n t [ i ] ; };

3.3 Binary Indexed Tree / Fenwick Tree


Resolve queries do tipo RSQ de 1 a n (1-indexed) em O(logn). Update pontual em O(logn).

#include <v e c t o r > while ( i > 0 ) {


using namespace s t d ; sum = comp ( sum , f t [ i ] ) ;
i −= ( i & − i ) ;
const i n t n e u t r a l = 0 ; }
i n t comp ( i n t a , i n t b ) { return sum ;
return a+b ; }
} int rsq ( int i , int j ) {
return r s q ( j ) − r s q ( i − 1 ) ;
c l a s s FenwickTree { }
private : void update ( i n t i , i n t v ) {
v e c t o r <int> f t ; while ( i < ( i n t ) f t . s i z e ( ) ) {
public : f t [ i ] = comp ( v , f t [ i ] ) ;
FenwickTree ( i n t n ) { i += ( i & − i ) ;
f t . a s s i g n ( n + 1 , 0 ) ; //1−i n d e x e d }
} }
i n t r s q ( i n t i ) { // r e t u r n s RSQ( 1 , i ) };
i n t sum = n e u t r a l ;

3.4 Binary Indexed Tree / Fenwick Tree com range updates e queries
Resolve queries do tipo RSQ de i a j (1-indexed) em O(logn). Range updates (a[i...j]+ = v) em O(logn).

#include <v e c t o r > }


using namespace s t d ; public :
FenwickTree ( i n t n ) {
c l a s s FenwickTree { f t 1 . a s s i g n (n + 1 , 0) ; //1−i n d e x e d
private : f t 2 . a s s i g n (n + 1 , 0) ; //1−i n d e x e d
v e c t o r <int> f t 1 , f t 2 ; }
i n t r s q ( v e c t o r <int> & f t , i n t i ) { void update ( i n t i , i n t j , i n t v ) {
i n t sum = 0 ; update ( f t 1 , i , v ) ;
while ( i > 0 ) { update ( f t 1 , j +1 , −v ) ;
sum += f t [ i ] ; update ( f t 2 , i , v ∗ ( i −1) ) ;
i −= ( i & − i ) ; update ( f t 2 , j +1 , −v∗ j ) ;
} }
return sum ; int rsq ( int i ) {
} return r s q ( f t 1 , i ) ∗ i − r s q ( f t 2 , i ) ;
void update ( v e c t o r <int> & f t , i n t i , i n t v ) { }
while ( i < ( i n t ) f t . s i z e ( ) ) { int rsq ( int i , int j ) {
f t [ i ] += v ; return r s q ( j ) − r s q ( i −1) ;
i += ( i & − i ) ; }
} };
CAPÍTULO 3. ESTRUTURAS DE DADOS 14

3.5 Segment Tree


Árvore de segmentos em 1D.

#include <c s t d i o > }


#include <v e c t o r > int f i n d ( int p , int l , int r , int a , int b ) {
#include <a l g o r i t h m > i f ( a > r | | b < l ) return n e u t r a l ;
#define INF (1<<30) i f ( l >= a && r <= b ) return s t [ p ] ;
using namespace s t d ; i n t p1 = f i n d ( l e f t ( p ) , l , ( l + r ) / 2 , a , b ) ;
i n t p2 = f i n d ( r i g h t ( p ) , ( l + r ) / 2 + 1 , r , a ,
const i n t n e u t r a l = 0 ; b) ;
i n t comp ( i n t a , i n t b ) { return comp ( p1 , p2 ) ;
return a+b ; }
} public :
SegmentTree ( i n t ∗ b e g i n , i n t ∗ end ) {
c l a s s SegmentTree { s i z e = ( i n t ) ( end − b e g i n ) ;
private : s t . a s s i g n (4 ∗ s i z e , n e u t r a l ) ;
v e c t o r <int> s t , pos ; pos . a s s i g n ( s i z e + 9 , 0 ) ;
int s i z e ; build (1 , 0 , s i z e − 1 , begin ) ;
#define p a r e n t ( p ) ( p >> 1 ) }
#define l e f t ( p ) ( p << 1 ) i n t query ( i n t a , i n t b ) { return f i n d ( 1 , 0 , s i z e
#define r i g h t ( p ) ( ( p << 1 ) + 1 ) − 1 , a , b) ; }
void b u i l d ( i n t p , i n t l , i n t r , i n t ∗ A) { void update ( i n t n , i n t num) {
i f ( l == r ) { s t [ pos [ n ] ] = num ;
s t [ p ] = A[ l ] ; n = p a r e n t ( pos [ n ] ) ;
pos [ l ] = p ; while ( n>0) {
} s t [ n ] = comp ( s t [ l e f t ( n ) ] , s t [ r i g h t ( n ) ] ) ;
else { n = parent (n) ;
build ( l e f t (p) , l , ( l + r ) / 2 , A) ; }
build ( right (p) , ( l + r ) / 2 + 1 , r , A) ; }
s t [ p ] = comp ( s t [ l e f t ( p ) ] , st [ right (p) ] ) ; };
}

3.6 Segment Tree com Lazy Propagation


#include <c s t d i o > }
#include <v e c t o r > void update ( i n t p , i n t l , i n t r , i n t a , i n t b ,
#include <a l g o r i t h m > int k ) {
#define INF (1<<30) push ( p , l , r ) ;
using namespace s t d ; i f ( a > r | | b < l ) return ;
e l s e i f ( l >= a && r <= b ) {
const i n t n e u t r a l = 0 ; //comp ( x , n e u t r a l ) = x l a z y [ p ] = k ; push ( p , l , r ) ;
i n t comp ( i n t a , i n t b ) { }
return a + b ; else {
} update ( l e f t ( p ) , l , ( l + r ) / 2 , a , b , k ) ;
update ( r i g h t ( p ) , ( l + r ) / 2 + 1 , r , a , b ,
c l a s s SegmentTree { k) ;
private : s t [ p ] = comp ( s t [ l e f t ( p ) ] , s t [ r i g h t ( p ) ] ) ;
v e c t o r <int> s t , l a z y ; }
int s i z e ; }
#define p a r e n t ( p ) ( p >> 1 ) i n t query ( i n t p , i n t l , i n t r , i n t a , i n t b ) {
#define l e f t ( p ) ( p << 1 ) push ( p , l , r ) ;
#define r i g h t ( p ) ( ( p << 1 ) + 1 ) i f ( a > r | | b < l ) return n e u t r a l ;
void b u i l d ( i n t p , i n t l , i n t r , i n t ∗ A) { i f ( l >= a && r <= b ) return s t [ p ] ;
i f ( l == r ) { i n t p1 = query ( l e f t ( p ) , l , ( l + r ) / 2 , a , b ) ;
s t [ p ] = A[ l ] ; i n t p2 = query ( r i g h t ( p ) , ( l + r ) / 2 + 1 , r , a
} , b) ;
else { return comp ( p1 , p2 ) ;
b u i l d ( l e f t ( p ) , l , ( l + r ) / 2 , A) ; }
b u i l d ( r i g h t ( p ) , ( l + r ) / 2 + 1 , r , A) ; public :
s t [ p ] = comp ( s t [ l e f t ( p ) ] , s t [ r i g h t ( p ) ] ) ; SegmentTree ( i n t ∗ b e g i n , i n t ∗ end ) {
} s i z e = ( i n t ) ( end − b e g i n ) ;
} s t . a s s i g n (4 ∗ s i z e , n e u t r a l ) ;
void push ( i n t p , i n t l , i n t r ) { lazy . a s s i g n (4 ∗ s i z e , 0) ;
s t [ p ] += ( r − l + 1 ) ∗ l a z y [ p ] ; // Caso RSQ build (1 , 0 , s i z e − 1 , begin ) ;
// s t [ p ] += l a z y [ p ] ; // Caso RMQ }
i f ( l != r ) { i n t query ( i n t a , i n t b ) { return query ( 1 , 0 , s i z e
l a z y [ r i g h t ( p ) ] += l a z y [ p ] ; − 1 , a , b) ; }
l a z y [ l e f t ( p ) ] += l a z y [ p ] ; void update ( i n t a , i n t b , i n t k ) { update ( 1 , 0 ,
} size − 1 , a , b , k) ; }
lazy [ p ] = 0; };
CAPÍTULO 3. ESTRUTURAS DE DADOS 15

3.7 2D Binary Indexed Tree / Fenwick Tree


#include <v e c t o r > sum = comp ( sum , f t [ i ] [ j ] ) ;
using namespace s t d ; j −= ( j & −j ) ;
const i n t n e u t r a l = 0 ; }
i n t comp ( i n t a , i n t b ) { i −= ( i & − i ) ;
return a+b ; }
} return sum ;
c l a s s FenwickTree2D { }
private : void update ( i n t i , i n t j , i n t v ) {
v e c t o r < v e c t o r <int> > f t ; i n t _j = j ;
public : while ( i < ( i n t ) f t . s i z e ( ) ) { j = _j ;
FenwickTree2D ( i n t n , i n t m) { while ( j < ( i n t ) f t [ i ] . s i z e ( ) ) {
f t . a s s i g n ( n + 1 , v e c t o r <int >(m + 1 , 0 ) ) ; //1− f t [ i ] [ j ] = comp ( v , f t [ i ] [ j ] ) ;
indexed j += ( j & −j ) ;
} }
i n t r s q ( i n t i , i n t j ) { // r e t u r n s RSQ( ( 1 , 1 ) , ( i , i += ( i & − i ) ;
j)) }
i n t sum = 0 , _j = j ; }
while ( i > 0 ) { j = _j ; };
while ( j > 0 ) {

3.8 2D Segment Tree


#include <v e c t o r > i f ( l y >= i y && r y <= j y ) return s t [ px ] [ py ] ;
using namespace s t d ; i n t my = ( l y + r y ) / 2 ;
#define INF (1<<30) i n t p1y = queryy ( px , l e f t ( py ) , l y , my) ;
const i n t n e u t r a l = 0 ; i n t p2y = queryy ( px , r i g h t ( py ) , my+1 , r y ) ;
i n t comp ( i n t a , i n t b ) { return comp ( p1y , p2y ) ;
return a+b ; }
} void updatex ( i n t px , i n t l x , i n t r x ) {
c l a s s SegmentTree2D { i f ( l x > x | | r x < x ) return ;
i n t s i z e x , s i z e y , i x , jx , i y , jy , x , y , v ; i f ( l x < rx ) {
v e c t o r < v e c t o r <int> > s t ; i n t mx = ( l x + r x ) / 2 ;
#define p a r e n t ( p ) ( p >> 1 ) updatex ( l e f t ( px ) , l x , mx) ;
#define l e f t ( p ) ( p << 1 ) updatex ( r i g h t ( px ) , mx+1 , r x ) ;
#define r i g h t ( p ) ( ( p << 1 ) + 1 ) }
void b u i l d x ( i n t px , i n t l x , i n t rx , v e c t o r < updatey ( px , l x , rx , 1 , 0 , s i z e y −1) ;
v e c t o r <int> > & A) { }
i f ( l x != r x ) { void updatey ( i n t px , i n t l x , i n t rx , i n t py , i n t
i n t mx = ( l x + r x ) / 2 ; ly , int ry ) {
b u i l d x ( l e f t ( px ) , l x , mx, A) ; i f ( l y > y | | r y < y ) return ;
b u i l d x ( r i g h t ( px ) , mx+1 , rx , A) ; i f ( l y == r y ) {
} i f ( l x == r x ) s t [ px ] [ py ] = v ;
b u i l d y ( px , l x , rx , 1 , 0 , s i z e y −1 , A) ; e l s e s t [ px ] [ py ] = comp ( s t [ l e f t ( px ) ] [ py ] , s t [
} r i g h t ( px ) ] [ py ] ) ;
void b u i l d y ( i n t px , i n t l x , i n t rx , i n t py , i n t }
l y , i n t ry , v e c t o r < v e c t o r <int> > & A) { else {
i f ( l y == r y ) { i n t my = ( l y + r y ) / 2 ;
i f ( l x == r x ) s t [ px ] [ py ] = A[ l x ] [ l y ] ; updatey ( px , l x , rx , l e f t ( py ) , l y , my) ;
e l s e s t [ px ] [ py ] = comp ( s t [ l e f t ( px ) ] [ py ] , s t updatey ( px , l x , rx , r i g h t ( py ) , my+1 , r y ) ;
[ r i g h t ( px ) ] [ py ] ) ; s t [ px ] [ py ] = comp ( s t [ px ] [ l e f t ( py ) ] , s t [ px ] [
} r i g h t ( py ) ] ) ;
else { }
i n t my = ( l y + r y ) / 2 ; }
b u i l d y ( px , l x , rx , l e f t ( py ) , l y , my, A) ; public :
b u i l d y ( px , l x , rx , r i g h t ( py ) , my+1 , ry , A) ; SegmentTree2D ( v e c t o r < v e c t o r <int> > & A) {
s t [ px ] [ py ] = comp ( s t [ px ] [ l e f t ( py ) ] , s t [ px ] [ s i z e x = A. s i z e ( ) ;
r i g h t ( py ) ] ) ; sizey = A[ 0 ] . size () ;
} s t . a s s i g n ( 4 ∗ s i z e x +9 , v e c t o r <int >(4∗ s i z e y +9) ) ;
} b u i l d x ( 1 , 0 , s i z e x −1 , A) ;
i n t queryx ( i n t px , i n t l x , i n t r x ) { }
i f ( l x > j x | | r x < i x ) return n e u t r a l ; void update ( i n t _x , i n t _y , i n t _v) {
i f ( l x >= i x && r x <= j x ) return queryy ( px , 1 , x = _x ; y = _y ; v = _v ;
0 , s i z e y −1) ; updatex ( 1 , 0 , s i z e x − 1 ) ;
i n t mx = ( l x + r x ) / 2 ; }
i n t p1x = queryx ( l e f t ( px ) , l x , mx) ; i n t query ( i n t l x , i n t rx , i n t l y , i n t r y ) {
i n t p2x = queryx ( r i g h t ( px ) , mx+1 , r x ) ; i x = l x ; jx = rx ; i y = l y ; j y = ry ;
return comp ( p1x , p2x ) ; return queryx ( 1 , 0 , s i z e x − 1 ) ;
} }
i n t queryy ( i n t px , i n t py , i n t l y , i n t r y ) { };
i f ( l y > j y | | r y < i y ) return n e u t r a l ;
CAPÍTULO 3. ESTRUTURAS DE DADOS 16

3.9 Treap / Cartesian Tree


Treap simples, suporta operações da BST (insert, count, erase, nth_element). Propriedades:

• É 10 vezes mais lento que Red-Black Tree, só usar se for estritamente necessário.
• Se os valores de y forem os valores de uma array e x a posição, as queries de máximo se tornam queries de LCA.
• IMPORTANTE: split separa entre k-1 e k.
• nth_element é 1-indexed.
• Não suporta valores repetidos de x.

#include <c s t d i o > return b ;


#include <s e t > }
#include <a l g o r i t h m > }
using namespace s t d ; node ∗ count ( node ∗ t , i n t k ) {
i f ( t == NULL) return NULL;
struct node { e l s e i f ( k < t−>x ) return count ( t−>l , k ) ;
int x , y , s i z e ; e l s e i f ( k == t−>x ) return t ;
node ∗ l , ∗ r ; e l s e return count ( t−>r , k ) ;
node ( i n t _x) { }
x = _x ; i n t s i z e ( node ∗ t ) {
y = rand ( ) ; i f ( t == NULL) return 0 ;
size = 1; e l s e return t−>s i z e ;
l = r = NULL; }
} node ∗ nth_element ( node ∗ t , i n t n ) {
}; i f ( t == NULL) return NULL;
i f ( n <= s i z e ( t−>l ) ) return nth_element ( t−>l , n
c l a s s Treap { );
private : e l s e i f ( n == s i z e ( t−>l ) + 1 ) return t ;
node ∗ r o o t ; e l s e return nth_element ( t−>r , n−s i z e ( t−>l ) −1) ;
void r e f r e s h ( node ∗ t ) { }
i f ( t == NULL) return ; void d e l ( node ∗ &t ) {
t−>s i z e = 1 ; i f ( t == NULL) return ;
i f ( t−>l != NULL) i f ( t−>l != NULL) d e l ( t−>l ) ;
t−>s i z e += t−>l −>s i z e ; i f ( t−>r != NULL) d e l ( t−>r ) ;
i f ( t−>r != NULL) delete t ;
t−>s i z e += t−>r−>s i z e ; t = NULL;
} }
void s p l i t ( node ∗ &t , i n t k , node ∗ &a , node ∗ &b ) { public :
node ∗ aux ; Treap ( ) { r o o t = NULL; }
i f ( t == NULL) { ~Treap ( ) { c l e a r ( ) ; }
a = b = NULL; void c l e a r ( ) { d e l ( r o o t ) ; }
return ; i n t s i z e ( ) { return s i z e ( r o o t ) ; }
} bool count ( i n t k ) { return count ( r o o t , k ) != NULL;
e l s e i f ( t−>x < k ) { }
s p l i t ( t−>r , k , aux , b ) ; bool i n s e r t ( i n t k ) {
t−>r = aux ; i f ( count ( r o o t , k ) != NULL) return f a l s e ;
refresh ( t ) ; node ∗a , ∗b , ∗ c , ∗d ;
a = t; s p l i t ( root , k , a , b) ;
} c = new node ( k ) ;
else { d = merge ( a , c ) ;
s p l i t ( t−>l , k , a , aux ) ; r o o t = merge ( d , b ) ;
t−>l = aux ; return true ;
refresh ( t ) ; }
b = t; bool e r a s e ( i n t k ) {
} node ∗ f = count ( r o o t , k ) ;
} i f ( f == NULL) return f a l s e ;
node ∗ merge ( node ∗ &a , node ∗ &b ) { node ∗a , ∗b , ∗ c , ∗d ;
node ∗ aux ; s p l i t ( root , k , a , b) ;
i f ( a == NULL) return b ; s p l i t ( b , k+1 , c , d ) ;
e l s e i f ( b == NULL) return a ; r o o t = merge ( a , d ) ;
i f ( a−>y < b−>y ) { delete f ;
aux = merge ( a−>r , b ) ; return true ;
a−>r = aux ; }
refresh (a) ; i n t nth_element ( i n t n ) {
return a ; node ∗ ans = nth_element ( r o o t , n ) ;
} i f ( ans == NULL) return −1;
else { e l s e return ans−>x ;
aux = merge ( a , b−>l ) ; }
b−>l = aux ; };
refresh (b) ;
CAPÍTULO 3. ESTRUTURAS DE DADOS 17

3.10 Treap / Cartesian Tree implícita


Suporta operações do vector, da SegmentTree e reverse em O(logn) (insertAt, erase, at, query, reverse). Propriedades:

• Pode trocar trechos do vetor de lugar com split e merge.


• IMPORTANTE: split separa em árvores de tamanho k e size − k.
• at é 0-indexed.

#include <c s t d i o > }


#include <a l g o r i t h m > }
#define INF ( 1 << 3 0 ) node ∗ merge ( node ∗ &a , node ∗ &b ) {
using namespace s t d ; refresh (a) ;
refresh (b) ;
const i n t n e u t r a l = 0 ; //comp ( x , n e u t r a l ) = x node ∗ aux ;
i n t comp ( i n t a , i n t b ) { i f ( a == NULL) return b ;
return a + b ; e l s e i f ( b == NULL) return a ;
} i f ( a−>y < b−>y ) {
aux = merge ( a−>r , b ) ;
struct node { a−>r = aux ;
i n t y , v , sum , s i z e ; refresh (a) ;
bool swap ; return a ;
node ∗ l , ∗ r ; }
node ( i n t _v) { else {
v = sum = _v ; aux = merge ( a , b−>l ) ;
y = rand ( ) ; b−>l = aux ;
size = 1; refresh (b) ;
l = r = NULL; return b ;
swap = f a l s e ; }
} }
}; node ∗ a t ( node ∗ t , i n t n ) {
i f ( t == NULL) return NULL;
class ImplicitTreap { refresh ( t ) ;
private : i f ( n < s i z e ( t−>l ) ) return a t ( t−>l , n ) ;
node ∗ r o o t ; e l s e i f ( n == s i z e ( t−>l ) ) return t ;
void r e f r e s h ( node ∗ t ) { e l s e return a t ( t−>r , n−s i z e ( t−>l ) −1) ;
i f ( t == NULL) return ; }
t−>s i z e = 1 ; i n t s i z e ( node ∗ t ) {
t−>sum = t−>v ; i f ( t == NULL) return 0 ;
i f ( t−>l != NULL) { e l s e return t−>s i z e ;
t−>s i z e += t−>l −>s i z e ; }
t−>sum = comp ( t−>sum , t−>l −>sum ) ; void d e l ( node ∗ &t ) {
t−>l −>swap ^= t−>swap ; i f ( t == NULL) return ;
} i f ( t−>l != NULL) d e l ( t−>l ) ;
i f ( t−>r != NULL) { i f ( t−>r != NULL) d e l ( t−>r ) ;
t−>s i z e += t−>r−>s i z e ; delete t ;
t−>sum = comp ( t−>sum , t−>r−>sum ) ; t = NULL;
t−>r−>swap ^= t−>swap ; }
} public :
i f ( t−>swap ) { I m p l i c i t T r e a p ( ) { r o o t = NULL; }
swap ( t−>l , t−>r ) ; ~ImplicitTreap () { clear () ; }
t−>swap = f a l s e ; void c l e a r ( ) { d e l ( r o o t ) ; }
} i n t s i z e ( ) { return s i z e ( r o o t ) ; }
} bool i n s e r t A t ( i n t n , i n t v ) {
void s p l i t ( node ∗ &t , i n t k , node ∗ &a , node ∗ &b ) { node ∗a , ∗b , ∗ c , ∗d ;
refresh ( t ) ; s p l i t ( root , n , a , b) ;
node ∗ aux ; c = new node ( v ) ;
i f ( t == NULL) { d = merge ( a , c ) ;
a = b = NULL; r o o t = merge ( d , b ) ;
return ; return true ;
} }
e l s e i f ( s i z e ( t−>l ) < k ) { bool e r a s e ( i n t n ) {
s p l i t ( t−>r , k−s i z e ( t−>l ) −1, aux , b ) ; node ∗a , ∗b , ∗ c , ∗d ;
t−>r = aux ; s p l i t ( root , n , a , b) ;
refresh ( t ) ; s p l i t (b , 1 , c , d) ;
a = t; r o o t = merge ( a , d ) ;
} i f ( c == NULL) return f a l s e ;
else { delete c ;
s p l i t ( t−>l , k , a , aux ) ; return true ;
t−>l = aux ; }
refresh ( t ) ; int at ( int n ) {
b = t; node ∗ ans = a t ( r o o t , n ) ;
CAPÍTULO 3. ESTRUTURAS DE DADOS 18

i f ( ans == NULL) return −1; }


e l s e return ans−>v ; void r e v e r s e ( i n t l , i n t r ) {
} i f ( l >r ) swap ( l , r ) ;
i n t query ( i n t l , i n t r ) { node ∗a , ∗b , ∗ c , ∗d ;
i f ( l >r ) swap ( l , r ) ; s p l i t ( root , l , a , d) ;
node ∗a , ∗b , ∗ c , ∗d ; s p l i t ( d , r−l +1 , b , c ) ;
s p l i t ( root , l , a , d) ; i f ( b != NULL) b−>swap ^= 1 ;
s p l i t ( d , r−l +1 , b , c ) ; d = merge ( b , c ) ;
i n t ans = ( b != NULL ? b−>sum : n e u t r a l ) ; r o o t = merge ( a , d ) ;
d = merge ( b , c ) ; }
r o o t = merge ( a , d ) ; };
return ans ;

3.11 Link Cut Tree


Estrutura de dados semelhante a disjoint sets que permite conectar vértices sem pai a algum outro vértice, cortar relação
com o pai e queries de raíz da árvore e LCA. Tudo em O(log 2 n).

#include <v e c t o r > node ∗q , ∗ r ;


using namespace s t d ; while ( p−>par != NULL) {
#define INF (1<<30) q = p−>par ;
i f ( q−>par == NULL) {
struct node i f ( p == q−> l e f t ) r o t a t e r i g h t ( p ) ;
{ i n t s i z e , id , w ; else r o t a t e l e f t (p) ;
node ∗ par , ∗ ppar , ∗ l e f t , ∗ r i g h t ; }
node ( ) { else {
par = ppar = l e f t = r i g h t = NULL; r = q−>par ;
w = s i z e = INF ; i f ( q == r−> l e f t ) {
} i f ( p == q−> l e f t ) r o t a t e r i g h t ( q ) ,
}; rotateright (p) ;
else r o t a t e l e f t (p) , r o t a t e r i g h t (p) ;
c l a s s LinkCutTree }
{ else {
v e c t o r <node> l c t ; i f ( p == q−>r i g h t ) r o t a t e l e f t ( q ) ,
r o t a t e l e f t (p) ;
void update ( node ∗ p ) { else r o t a t e r i g h t (p) , r o t a t e l e f t (p) ;
p−>s i z e = p−>w ; }
i f ( p−> l e f t ) p−>s i z e += p−>l e f t −>s i z e ; }
i f ( p−>r i g h t ) p−>s i z e += p−>r i g h t −>s i z e ; }
} update ( p ) ;
}
void r o t a t e r i g h t ( node ∗ p ) {
node ∗q , ∗ r ; node ∗ a c c e s s ( node ∗ p ) {
q = p−>par , r = q−>par ; splay (p) ;
i f ( ( q−> l e f t = p−>r i g h t ) ) q−>l e f t −>par = q ; i f ( p−>r i g h t != NULL) {
p−>r i g h t = q , q−>par = p ; p−>r i g h t −>ppar = p ;
i f ( ( p−>par = r ) ) { p−>r i g h t −>par = NULL;
i f ( q == r−> l e f t ) r−> l e f t = p ; p−>r i g h t = NULL;
e l s e r−>r i g h t = p ; update ( p ) ;
} }
p−>ppar = q−>ppar ; node ∗ l a s t = p ;
q−>ppar = NULL; while ( p−>ppar != NULL) {
update ( q ) ; node ∗ q = p−>ppar ;
} last = q;
splay (q) ;
void r o t a t e l e f t ( node ∗ p ) { i f ( q−>r i g h t != NULL) {
node ∗q , ∗ r ; q−>r i g h t −>ppar = q ;
q = p−>par , r = q−>par ; q−>r i g h t −>par = NULL;
i f ( ( q−>r i g h t = p−> l e f t ) ) q−>r i g h t −>par = q ; }
p−> l e f t = q , q−>par = p ; q−>r i g h t = p ;
i f ( ( p−>par = r ) ) p−>par = q ;
{ p−>ppar = NULL;
i f ( q == r−> l e f t ) r−> l e f t = p ; update ( q ) ;
e l s e r−>r i g h t = p ; splay (p) ;
} }
p−>ppar = q−>ppar ; return l a s t ;
q−>ppar = 0 ; }
update ( q ) ;
} public :
LinkCutTree ( ) { }
void s p l a y ( node ∗ p ) { LinkCutTree ( i n t n ) {
CAPÍTULO 3. ESTRUTURAS DE DADOS 19

l c t . r e s i z e (n + 1) ; p−> l e f t = NULL;
f o r ( i n t i = 0 ; i <= n ; i ++){ update ( p ) ;
l c t [ i ] . id = i ; }
update (& l c t [ i ] ) ;
} int f i n d r o o t ( int u ) {
} node ∗ p = &l c t [ u ] ;
access (p) ;
void l i n k ( i n t u , i n t v , i n t w) { //u becomes while ( p−> l e f t ) p = p−> l e f t ;
child of v splay (p) ;
node ∗p = &l c t [ u ] , ∗q = &l c t [ v ] ; return p−>i d ;
access (p) ; }
access (q) ;
p−> l e f t = q ; bool IsSameTree ( i n t u , i n t v ) {
q−>par = p ; return f i n d r o o t ( u ) == f i n d r o o t ( v ) ;
p−>w = w ; }
update ( p ) ;
} i n t depth ( i n t u ) {
a c c e s s (& l c t [ u ] ) ;
void l i n k ( i n t u , i n t v ) { // u n w e i g h t e d return l c t [ u ] . s i z e − l c t [ u ] . w ;
l i n k (u , v , 1) ; }
}
i n t LCA( i n t u , i n t v ) {
void c u t ( i n t u ) { a c c e s s (& l c t [ u ] ) ;
node ∗ p = &l c t [ u ] ; return a c c e s s (& l c t [ v ] )−>i d ;
access (p) ; }
p−>l e f t −>par = NULL; };

3.12 Link Cut Tree não direcionada


Semelhante a LinkCutT ree, porém permite o link e o cut de quaisquer vértices de forma não direcionada.. Tudo em
O(log 2 n).

struct node { . . . } ; }
c l a s s LinkCutTree { . . . }; void l i n k ( i n t u , i n t v ) {
i f ( l c t . depth ( u ) < l c t . depth ( v ) ) {
class UndirectedLinkCutTree invert (u) ;
{ l c t . link (u , v) ;
LinkCutTree l c t ; par [ u ] = v ;
v e c t o r <int> par ; }
else {
void i n v e r t ( i n t u ) { invert (v) ;
i f ( par [ u ] == −1) return ; l c t . link (v , u) ;
i n t v = par [ u ] ; par [ v ] = u ;
invert (v) ; }
l c t . cut (u) ; }
par [ u ] = −1; void c u t ( i n t u , i n t v ) {
l c t . link (v , u) ; i f ( par [ v ] == u ) u = v ;
par [ v ] = u ; l c t . cut (u) ;
} par [ u ] = −1;
public : }
U n d i r e c t e d L i n k C u t T r e e ( ) {} bool IsSameTree ( i n t u , i n t v ) {
UndirectedLinkCutTree ( int n ) { return l c t . IsSameTree ( u , v ) ;
l c t = LinkCutTree ( n ) ; }
par . a s s i g n ( n+1 , −1) ; };
CAPÍTULO 3. ESTRUTURAS DE DADOS 20

3.13 Splay Tree


Árvore de busca binária em que, para todas as operações, rotaciona-se a raíz até o elemento desejado chegar na raíz.

struct node { }
i n t key ; }
node ∗ l e f t , ∗ r i g h t ; void d e l ( node ∗ p ) {
node ( i n t k ) { i f ( ! p ) return ;
key = k ; l e f t = r i g h t = 0 ; d e l ( p−> l e f t ) ;
} d e l ( p−>r i g h t ) ;
}; delete p ;
}
class SplayTree {
private : public :
node ∗ r o o t ; SplayTree ( ) { root = 0 ; }
node ∗ r o t a t e r i g h t ( node ∗ p ) { ~S p l a y T r e e ( ) { d e l ( r o o t ) ; }
node ∗ q = p−> l e f t ; bool empty ( ) { return r o o t == NULL; }
p−> l e f t = q−>r i g h t ; void c l e a r ( ) {
q−>r i g h t = p ; del ( root ) ;
return q ; root = 0;
} }
node ∗ r o t a t e l e f t ( node ∗ q ) { void i n s e r t ( i n t key ) {
node ∗ p = q−>r i g h t ; i f ( ! root ){
q−>r i g h t = p−> l e f t ; r o o t = new node ( key ) ;
p−> l e f t = q ; return ;
return p ; }
} node ∗ p = s p l a y ( r o o t , key ) ;
node ∗ s p l a y ( node ∗ p , i n t key ) { i f ( p−>key == key ) return ;
i f ( p == NULL | | p−>key == key ) return p ; r o o t = new node ( key ) ;
i f ( p−>key > key ) { i f ( p−>key > key ) {
i f ( ! p−> l e f t ) return p ; r o o t −>r i g h t = p ;
i f ( p−>l e f t −>key > key ) { r o o t −> l e f t = p−> l e f t ;
p−>l e f t −> l e f t = s p l a y ( p−>l e f t −>l e f t , key p−> l e f t = NULL;
); }
p = rotateright (p) ; else {
} r o o t −> l e f t = p ;
e l s e i f ( p−>l e f t −>key < key ) { r o o t −>r i g h t = p−>r i g h t ;
p−>l e f t −>r i g h t = s p l a y ( p−>l e f t −>r i g h t , p−>r i g h t = NULL;
key ) ; }
i f ( p−>l e f t −>r i g h t ) }
p−> l e f t = r o t a t e l e f t ( p−> l e f t ) ; void e r a s e ( i n t key ) {
} node ∗ p = s p l a y ( r o o t , key ) ;
return ( p−> l e f t == NULL) ? p : r o t a t e r i g h t ( i f ( p != NULL && p−>key != key ) return ;
p) ; i f ( ! p−>r i g h t ) {
} r o o t = p−> l e f t ;
else { delete p ;
i f ( ! p−>r i g h t ) return p ; return ;
i f ( p−>r i g h t −>key > key ) { }
p−>r i g h t −> l e f t = s p l a y ( p−>r i g h t −>l e f t , node ∗ q = s p l a y ( p−>r i g h t , key ) ;
key ) ; q−> l e f t = p−> l e f t ;
i f ( p−>r i g h t −> l e f t ) root = q ;
p−>r i g h t = r o t a t e r i g h t ( p−>r i g h t ) ; delete p ;
} }
e l s e i f ( p−>r i g h t −>key < key ) { bool count ( i n t key ) {
p−>r i g h t −>r i g h t = s p l a y ( p−>r i g h t −>r i g h t , i f ( ! r o o t ) return f a l s e ;
key ) ; r o o t = s p l a y ( r o o t , key ) ;
p = r o t a t e l e f t (p) ; return r o o t −>key == key ;
} }
return ( p−>r i g h t == NULL) ? p : r o t a t e l e f t ( };
p) ;
CAPÍTULO 3. ESTRUTURAS DE DADOS 21

3.14 AVL Tree


struct node { i f ( p−> l e f t == 0 ) return p−>r i g h t ;
i n t key , h e i g h t , s i z e ; p−> l e f t = removemin ( p−> l e f t ) ;
node ∗ l e f t , ∗ r i g h t ; return b a l a n c e ( p ) ;
node ( i n t k ) { }
key = k ; l e f t = r i g h t = 0 ; node ∗ remove ( node ∗ p , i n t k ) {
height = s i z e = 1; i f ( ! p ) return 0 ;
} i f ( k < p−>key ) p−> l e f t = remove ( p−>l e f t , k ) ;
}; e l s e i f ( k > p−>key ) p−>r i g h t = remove ( p−>
right , k) ;
c l a s s AVLtree { else {
private : node ∗ l = p−> l e f t ;
node ∗ r o o t ; node ∗ r = p−>r i g h t ;
int size_ ; delete p ;
i n t h e i g h t ( node ∗ p ) { i f ( ! r ) return l ;
return p ? p−>h e i g h t : 0 ; node ∗ min = f i n d m i n ( r ) ;
} min−>r i g h t = removemin ( r ) ;
i n t s i z e ( node ∗ p ) { min−> l e f t = l ;
return p ? p−>s i z e : 0 ; return b a l a n c e ( min ) ;
} }
i n t b f a c t o r ( node ∗ p ) { return b a l a n c e ( p ) ;
return h e i g h t ( p−>r i g h t ) − h e i g h t ( p−> l e f t ) ; }
} bool f i n d ( node ∗ p , i n t k ) {
void f i x h e i g h t ( node ∗ p ) { i f ( ! p ) return f a l s e ;
i n t h l = h e i g h t ( p−> l e f t ) ; i f ( p−>key == k ) return true ;
i n t hr = h e i g h t ( p−>r i g h t ) ; e l s e i f ( k<p−>key ) return f i n d ( p−>l e f t , k ) ;
p−>h e i g h t = ( hl >hr ? h l : hr ) + 1 ; e l s e return f i n d ( p−>r i g h t , k ) ;
p−>s i z e = 1 + s i z e ( p−> l e f t ) + s i z e ( p−>r i g h t ) ; }
} void d e l ( node ∗ p ) {
node ∗ r o t a t e r i g h t ( node ∗ p ) { i f ( ! p ) return ;
node ∗ q = p−> l e f t ; d e l ( p−> l e f t ) ;
p−> l e f t = q−>r i g h t ; d e l ( p−>r i g h t ) ;
q−>r i g h t = p ; delete p ;
fixheight (p) ; }
fixheight (q) ; node ∗ nth ( node ∗ p , i n t n ) {
return q ; i f ( ! p ) return p ;
} i f ( s i z e ( p−> l e f t ) + 1 > n ) return nth ( p−>l e f t ,
node ∗ r o t a t e l e f t ( node ∗ q ) { n) ;
node ∗ p = q−>r i g h t ; i f ( s i z e ( p−> l e f t ) + 1 < n ) return nth ( p−>r i g h t
q−>r i g h t = p−> l e f t ; , n − s i z e ( p−> l e f t ) − 1 ) ;
p−> l e f t = q ; e l s e return p ;
fixheight (q) ; }
fixheight (p) ;
return p ; public :
} AVLtree ( ) { r o o t = 0 ; s i z e _ = 0 ; }
node ∗ b a l a n c e ( node ∗ p ) { ~AVLtree ( ) { d e l ( r o o t ) ; }
fixheight (p) ; bool empty ( ) { return s i z e _ == 0 ; }
i f ( b f a c t o r ( p ) == 2 ) { i n t s i z e ( ) { return s i z e _ ; }
i f ( b f a c t o r ( p−>r i g h t ) <0) void c l e a r ( ) {
p−>r i g h t = r o t a t e r i g h t ( p−>r i g h t ) ; size_ = 0;
return r o t a t e l e f t ( p ) ; del ( root ) ;
} root = 0;
i f ( b f a c t o r ( p ) == −2) { }
i f ( b f a c t o r ( p−> l e f t ) >0) void i n s e r t ( i n t key ) {
p−> l e f t = r o t a t e l e f t ( p−> l e f t ) ; s i z e _ ++;
return r o t a t e r i g h t ( p ) ; r o o t = b u i l d ( r o o t , key ) ;
} }
return p ; void e r a s e ( i n t key ) {
} s i z e _ −−;
node ∗ b u i l d ( node ∗ p , i n t k ) { r o o t = remove ( r o o t , key ) ;
i f ( ! p ) return new node ( k ) ; }
i f ( p−>key == k ) return p ; bool count ( i n t key ) {
e l s e i f ( k<p−>key ) p−> l e f t = b u i l d ( p−>l e f t , k ) return f i n d ( r o o t , key ) ;
; }
e l s e p−>r i g h t = b u i l d ( p−>r i g h t , k ) ; i n t nth_element ( i n t n ) {
return b a l a n c e ( p ) ; node ∗ p = nth ( r o o t , n ) ;
} i f ( p ) return p−>key ;
node ∗ f i n d m i n ( node ∗ p ) { e l s e return −1;
return p−> l e f t ? f i n d m i n ( p−> l e f t ) : p ; } //1−i n d e x e d
} };
node ∗ removemin ( node ∗ p ) {
CAPÍTULO 3. ESTRUTURAS DE DADOS 22

3.15 Heavy-Light Decomposition


Decomposição Heavy-light de uma árvore em O(n). Query de LCA em O(logn). chain[i] é a i-ésima cadeia. nchs é o número
de cadeias. nchain[u] é o índice da cadeia a qual u pertence. up[i] é o índice do nó do qual a i-ésima cadeia é filha. id[u] é o
índice de nó u dentro de sua cadeia. f son[u] é o filho de u por onde a cadeia atual prossegue. depth[i] é a profundidade do
nó mais alto da i-ésima cadeia. Para queries de distância e outras, montar SegTrees, BIT’s ou somas parciais por cadeia.

#include <v e c t o r > i f ( v == par [ u ] ) continue ;


using namespace s t d ; i f ( v == f s o n [ u ] ) b u i l d d f s ( v , ch , h+1) ;
#define MAXN 100009 else {
up [ nchs ] = u ; depth [ nchs ] = h ;
i n t par [MAXN] , s i z e [MAXN] ; c h a i n [ nchs ] . c l e a r ( ) ;
v e c t o r <int> a d j L i s t [MAXN] ; b u i l d d f s ( v , nchs++, h+1) ;
i n t r o o t , N, up [MAXN] , f s o n [MAXN] ; }
v e c t o r <int> c h a i n [MAXN] ; }
i n t nchs , n c h a i n [MAXN] , i d [MAXN] , depth [MAXN] ; }

int s i z e d f s ( int u , int p ) { void h e a v y l i g h t d e c o m p o s i t i o n ( i n t _root ) {


s i z e [ u ] = 1 ; f s o n [ u ] = −1; par [ u ] = p ; r o o t = _root ;
i n t msz = 0 ; s i z e d f s ( r o o t , −1) ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++) { nchs = 0 ; c h a i n [ 0 ] . c l e a r ( ) ;
int v = a d j L i s t [ u ] [ i ] ; up [ nchs ] = −1; depth [ nchs ] = 0 ;
i f ( v == p ) continue ; b u i l d d f s ( r o o t , nchs++, 1 ) ;
s i z e [ u ] += s i z e d f s ( v , u ) ; }
i f ( s i z e [ v ] > msz ) {
f s o n [ u ] = v ; msz = s i z e [ v ] ; i n t LCA( i n t u , i n t v ) {
} i n t cu = n c h a i n [ u ] , cv = n c h a i n [ v ] ;
} while ( cu != cv ) {
return s i z e [ u ] ; i f ( depth [ cu ] > depth [ cv ] ) u = up [ cu ] ;
} e l s e v = up [ cv ] ;
cu = n c h a i n [ u ] ; cv = n c h a i n [ v ] ;
void b u i l d d f s ( i n t u , i n t ch , i n t h ) { }
n c h a i n [ u ] = ch ; i d [ u ] = c h a i n [ ch ] . s i z e ( ) ; i f ( i d [ u ] < i d [ v ] ) return u ;
c h a i n [ ch ] . push_back ( u ) ; e l s e return v ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){ }
int v = a d j L i s t [ u ] [ i ] ;

3.16 Centroid Decomposition


Realiza a decomposição em O(nlogn) e retorna a raíz da decomposição. csons[i] são os filhos do i-ésimo nó segundo a
decomposição. par[i] é o pai do i-ésimo nó segundo a decomposição. label[i] é a profundidade do i-ésimo nó na decomposição,
iniciando em 0. size[i] no final do algoritmo contém o tamanho da subárvore de centróides com raíz i.
CUIDADO: o pai da raiz da árvore centróide é ele mesmo.

#include <c s t r i n g > return f i n d c e n t r o i d ( v , u , nn ) ;


#include <v e c t o r > }
using namespace s t d ; return u ;
#define MAXN 100009 }
i n t decompose ( i n t r o o t , i n t par ) {
typedef long long l l ; s u b s i z e ( r o o t , −1) ;
typedef p a i r <l l , int> i i ; i n t u = f i n d c e n t r o i d ( r o o t , −1, c s i z e [ r o o t ] ) ;
i n t c l e v e l [MAXN] , c p a r [MAXN] , c s i z e [MAXN] ; c p a r [ u ] = par ;
v e c t o r <int> c s o n s [MAXN] ; c l e v e l [ u ] = par >= 0 ? c l e v e l [ par ]+1 : 0 ;
v e c t o r <i i > a d j L i s t [MAXN] ; csize [ u ] = 1;
i n t N, K; f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){
int v = a d j L i s t [ u ] [ i ] . second ;
int s u b s i z e ( int u , int p ) { i f ( v != par && c l e v e l [ v ] < 0 ) {
c s i z e [ u]=1; v = decompose ( v , u ) ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){ c s o n s [ u ] . push_back ( v ) ;
int v = a d j L i s t [ u ] [ i ] . second ; c s i z e [ u ] += c s i z e [ v ] ;
i f ( v != p && c l e v e l [ v ] < 0 ) }
c s i z e [ u ] += s u b s i z e ( v , u ) ; }
} return u ;
return c s i z e [ u ] ; }
} int c e n t r o i d d e c o m p o s it i o n ( int root ) {
i n t f i n d c e n t r o i d ( i n t u , i n t p , i n t nn ) { memset(& c l e v e l , −1, s i z e o f c l e v e l ) ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){ f o r ( i n t i =0; i <=N; i ++) c s o n s [ i ] . c l e a r ( ) ;
int v = a d j L i s t [ u ] [ i ] . second ; return decompose ( r o o t , −1) ;
i f ( v != p && c l e v e l [ v ] < 0 && c s i z e [ v ] > nn }
/2)
CAPÍTULO 3. ESTRUTURAS DE DADOS 23

3.17 Convex Hull Trick


Para queries de mínimo, sete maxCH = f alse e insira retas do tipo y = mx + n na ordem decrescente de m. Resolve
queries de min(y(x)) para todas as retas inseridas em tempo O(logn).
Para queries de máximo, sete maxCH = true e insira retas do tipo y = mx + n na ordem crescente de m. Resolve queries
de max(y(x)) para todas as retas inseridas em tempo O(logn).

#include <c s t d i o > p . back ( ) >= i n t e r (nm, nn , m. back ( ) , n .


#include <v e c t o r > back ( ) ) ) ) {
#define INF (1<<30) m. pop_back ( ) ; n . pop_back ( ) ; p . pop_back ( )
#define MAXN 1009 ;
using namespace s t d ; }
p . push_back ( p . empty ( ) ? −INF : i n t e r (nm, nn ,
typedef long long i n t l l ; m. back ( ) , n . back ( ) ) ) ;
m. push_back (nm) ; n . push_back ( nn ) ;
c l a s s CHTrick { }
private : l l query ( l l x ) {
v e c t o r <l l > m, n ; i f ( p . empty ( ) ) return (maxCH? −1:1) ∗INF ;
v e c t o r <double> p ; double dx = ( double ) x ;
bool maxCH ; l l h i g h = p . s i z e ( ) −1, low = 0 , mid ;
public : i f ( dx >= p [ h i g h ] ) return m[ h i g h ] ∗ x + n [ h i g h
CHTrick ( bool _maxCH) { maxCH = _maxCH; } ];
void c l e a r ( ) { while ( h i g h > low +1){
m. c l e a r ( ) ; n . c l e a r ( ) ; p . c l e a r ( ) ; mid = ( h i g h+low ) / 2 ;
} i f ( dx < p [ mid ] ) h i g h = mid ;
double i n t e r ( double nm, double nn , double lm , e l s e low = mid ;
double l n ) { }
return ( l n − nn ) / (nm − lm ) ; return m[ low ] ∗ x + n [ low ] ;
} }
void push ( l l nm, l l nn ) { };
while ( ! p . empty ( ) &&
( (nm == m. back ( ) && (maxCH? −1:1) ∗nn <= (
maxCH? −1:1) ∗n . back ( ) ) | |

3.18 Lowest Commom Ancestor (LCA) e distância na árvore


P [i][j] = o 2j -ésimo pai do i-ésimo nó. computeP (root) computa a matriz P em O(nlogn). A partir de P , pode-se calcular o
LCA de dois nós em O(log 2 n) para uma árvore qualquer com raiz em root. dist usa LCA pra calcular a query de distância
em O(log 2 n).

#include <v e c t o r > l e v e l [ r o o t ]= depth [ r o o t ] = 0 ;


#include <i o s t r e a m > P[ root ][0]= root ;
using namespace s t d ; depthdfs ( root ) ;
#define MAXN 100009 f o r ( i n t j = 1 ; j < MAXLOGN; j ++)
#define MAXLOGN 20 f o r ( i n t i = 1 ; i <= N; i ++)
P[ i ] [ j ] = P[P[ i ] [ j − 1 ] ] [ j −1];
typedef p a i r <int , int> i i ; }
v e c t o r <i i > a d j L i s t [MAXN] ; i n t LCA( i n t a , i n t b ) {
i n t depth [MAXN] , l e v e l [MAXN] ; i f ( l e v e l [ a ] > l e v e l [ b ] ) swap ( a , b ) ;
i n t P [MAXN] [MAXLOGN] , N; int d = l e v e l [ b ] − l e v e l [ a ] ;
f o r ( i n t i =0; i <MAXLOGN; i ++){
void d e p t h d f s ( i n t u ) { i f ( ( d & (1<< i ) ) != 0 ) b = P [ b ] [ i ] ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){ }
int v = a d j L i s t [ u ] [ i ] . f i r s t ; i f ( a == b ) return a ;
int w = a d j L i s t [ u ] [ i ] . second ; f o r ( i n t i = MAXLOGN−1; i >=0; i −−)
i f ( v == P [ u ] [ 0 ] ) continue ; while (P [ a ] [ i ] != P [ b ] [ i ] ) {
P[ v ] [ 0 ] = u ; a=P [ a ] [ i ] ; b=P [ b ] [ i ] ;
level [v] = 1 + level [u ]; }
depth [ v ] = w + depth [ u ] ; return P [ a ] [ 0 ] ;
depthdfs (v) ; }
} int d i s t ( int u , int v ) {
} return depth [ u ] + depth [ v ] − 2∗ depth [LCA( u , v ) ] ;
void computeP ( i n t r o o t ) { }
CAPÍTULO 3. ESTRUTURAS DE DADOS 24

3.19 Merge Sort Tree


Constrói a árvore de recursão do merge-sort. O(nlogn) em espaço e em tempo de contrução. Queries:

• O número de elementos menores que k em um intervalo (a, b) em O(log 2 n).


• O n-ésimo elemento 0-indexed em um intervalo (a, b) em O(log 3 n).

#include <v e c t o r > i f ( s t [ p ] [ 0 ] >= k | | a > r | | b < l ) return 0 ;


#define INF (1<<30) i f ( l >= a && r <= b ) {
using namespace s t d ; l = 0 ; r = ( int ) s t [ p ] . s i z e ( ) ;
i n t m;
c l a s s MergeSortTree { while ( r > l + 1 ) {
private : m = ( r+l ) / 2 ;
v e c t o r < v e c t o r <int> > s t ; i f ( s t [ p ] [ m] < k ) l = m;
int s i z e ; e l s e r = m;
#d e f i n e p a r e n t ( p ) ( p >> 1 ) }
#d e f i n e l e f t ( p ) ( p << 1 ) return r ;
#d e f i n e r i g h t ( p ) ( ( p << 1 ) + 1 ) }
void b u i l d ( i n t p , i n t l , i n t r , i n t ∗ A) { // O( n ) i n t p1 = l e s s ( l e f t ( p ) , l , ( l+r ) / 2 , a , b , k ) ;
s t [ p ] . r e s i z e ( r−l +1) ; i n t p2 = l e s s ( r i g h t ( p ) , ( l+r ) /2+1 , r , a , b , k )
i f ( l == r ) { ;
s t [ p ] [ 0 ] = A[ l ] ; return p1+p2 ;
} }
else { public :
i n t p l = l e f t ( p ) , pr = r i g h t ( p ) , m = ( l+r ) MergeSortTree ( i n t ∗ b e g i n , i n t ∗ end ) {
/2; s i z e = ( i n t ) ( end−b e g i n ) ;
b u i l d ( p l , l , m, A) ; s t . a s s i g n ( 4 ∗ s i z e , v e c t o r <int >() ) ;
b u i l d ( pr , m+1 , r , A) ; b u i l d ( 1 , 0 , s i z e −1 , b e g i n ) ;
unsigned i n t i =0 , j =0 , k =0; }
while ( i < s t [ p l ] . s i z e ( ) && j < s t [ pr ] . s i z e int l e s s ( int a , int b , int k ) {
() ){ return l e s s ( 1 , 0 , s i z e −1 , a , b , k ) ;
i f ( s t [ p l ] [ i ] < s t [ pr ] [ j ] ) s t [ p ] [ k++] = }
s t [ p l ] [ i ++]; i n t nth_element ( i n t a , i n t b , i n t n ) {
e l s e s t [ p ] [ k++] = s t [ pr ] [ j ++]; i n t l = −INF , r = INF , m;
} while ( r > l +1){
while ( i < s t [ p l ] . s i z e ( ) ) s t [ p ] [ k++] = s t [ p l m = ( r+l ) / 2 ;
] [ i ++]; i f ( l e s s ( a , b , m) <= n ) l = m;
while ( j < s t [ pr ] . s i z e ( ) ) s t [ p ] [ k++] = s t [ pr e l s e r = m;
] [ j ++]; }
} return l ;
} }
int l e s s ( int p , int l , int r , int a , int b , int k };
) { // O( l o g n )

3.20 Sparse Table


Resolve queries do tipo RMQ de l a r em O(1). Pré-processamento O(nlogn).

#include <c s t d i o > s i z e = end − b e g i n ;


#include <cmath> f o r ( i n t i =0; i <s i z e ; i ++){
#define MAXN 100009 SpT [ i ] [ 0 ] = b e g i n [ i ] ;
#define MAXLOGN 20 }
f o r ( i n t j = 1 ; 1 << j <= s i z e ; j ++){
// comparison f u n c t i o n , can r e c l a c e w i t h min , max , f o r ( i n t i =0; i + (1<< j ) <= s i z e ; i ++){
gcd SpT [ i ] [ j ] = comp ( SpT [ i ] [ j − 1 ] , SpT [ i
i n t comp ( i n t a , i n t b ) { +(1<<( j −1) ) ] [ j −1]) ;
return min ( a , b ) ; }
} }
}
class SparseTable { i n t query ( i n t l , i n t r ) {
private : i n t k = ( i n t ) f l o o r ( l o g ( ( double ) r−l +1) / l o g
i n t SpT [MAXN] [MAXLOGN] ; ( 2 . 0 ) ) ; // 2^k <= ( j −i +1)
int s i z e ; return comp ( SpT [ l ] [ k ] , SpT [ r −(1<<k ) + 1 ] [ k ] ) ;
public : }
S p a r s e T a b l e ( i n t ∗ b e g i n , i n t ∗ end ) { };
CAPÍTULO 3. ESTRUTURAS DE DADOS 25

3.21 Código de Huffman


Constrói o autômato de Huffman: dado um conjunto de elementos, montar uma árvore cujas folhas são os elementos desse
conjunto, o pai é a soma dos filhos e a soma de todos os nós é mínima. Propriedades:
• O caminho da raíz até a folha é o código de Huffman (filho esquerdo -> menor nó -> 0, filho direito -> maior nó -> 1);
• Nenhum código é o prefixo de outro;
Pn−1
• Essencialmente ele minimiza: cost = i=0 a[i] × depth[i]

#include <queue> cu = −pq . top ( ) . f i r s t ;


#include <v e c t o r > pq . pop ( ) ;
using namespace s t d ; v = pq . top ( ) . s e c o n d ;
#define MAXN 100009 cv = −pq . top ( ) . f i r s t ;
#define INF ( 1LL<<60) pq . pop ( ) ;
r o o t = s i z e ++;
typedef long long l l ; l e f t [ r o o t ] = u ; par [ u ] = r o o t ;
typedef p a i r <l l , int> i i ; r i g h t [ r o o t ] = v ; par [ v ] = r o o t ;
c o s t += cu + cv ;
c l a s s HuffmanTree { pq . push ( i i (−cu−cv , r o o t ) ) ;
v e c t o r <int> l e f t , r i g h t , par ; }
int root , s i z e ; }
l l cost ; l l g e t C o s t ( ) { return c o s t ; }
i n t g e t S i z e ( ) { return s i z e ; }
public : void getCode ( i n t u , char∗ b u f f e r ) {
HuffmanTree ( i n t ∗ b e g i n , i n t ∗ end ) { v e c t o r <int> s ;
s i z e = ( i n t ) ( end − b e g i n ) ; while ( par [ u ] >= 0 ) {
int u , v ; i f ( l e f t [ par [ u ] ] == u ) s . push_back ( 0 ) ;
cost = 0; e l s e s . push_back ( 1 ) ;
l l cu , cv ; u = par [ u ] ;
l e f t . a s s i g n ( 2 ∗ s i z e +9 , −1) ; }
r i g h t . a s s i g n ( 2 ∗ s i z e +9 , −1) ; while ( ! s . empty ( ) ) {
par . a s s i g n ( 2 ∗ s i z e +9 , −1) ; ∗ b u f f e r = s . back ( ) + ’ 0 ’ ;
p r i o r i t y _ q u e u e <i i > pq ; b u f f e r ++; s . pop_back ( ) ;
f o r ( i n t i =0; i <s i z e ; i ++){ }
pq . push ( i i (− b e g i n [ i ] , i ) ) ; ∗ b u f f e r = ’ \0 ’ ;
} }
while ( pq . s i z e ( ) > 1 ) { };
u = pq . top ( ) . s e c o n d ;
Capítulo 4

Paradigmas

4.1 Merge Sort


Algoritmo O(nlogn) para ordenar o vetor em [a, b]. inv conta o número de inversões do bubble-sort nesse trecho.

#include <c s t d i o > i n t p=a , q=mid+1 , k=a ;


#define MAXN 100009 while ( p<=mid && q<=b ) {
i f ( v e t [ p]> v e t [ q ] ) {
typedef long long i n t l l ; aux [ k++]=v e t [ q ++];
l l inv ; i n v += ( l l ) ( q−k ) ;
i n t N, v e t [MAXN] , aux [MAXN] ; }
e l s e aux [ k++]=v e t [ p++];
void m e r g e s o r t ( i n t a , i n t b ) { }
i f ( a==b ) return ; while ( p<=mid ) aux [ k++]=v e t [ p++];
i n t mid = ( a+b ) / 2 ; while ( q<=b ) aux [ k++]=v e t [ q ++];
m e r g e s o r t ( a , mid ) ; f o r ( i n t i=a ; i <=b ; i ++) v e t [ i ]= aux [ i ] ;
m e r g e s o r t ( mid+1 , b ) ; }

4.2 Quick Sort


Algoritmo Expected O(nlogn) para ordenar o vetor em [a, b]. É o mais rápido conhecido.

#include <c s t d i o > while ( i <= j ) {


#include <a l g o r i t h m > while ( i <= j && a r r [ i ] <= p i v o t ) i ++;
using namespace s t d ; while ( i <= j && a r r [ j ] > p i v o t ) j −−;
if ( i < j ) swap ( a r r [ i ] , a r r [ j ] ) ;
void q u i c k s o r t ( i n t ∗ a r r , i n t l , i n t r ) { }
i f ( l >= r ) return ; swap ( a r r [ i − 1 ] , arr [ l ] ) ;
i n t mid = l + ( r − l ) / 2 ; q u i c k s o r t ( arr , l , i −2) ;
i n t p i v o t = a r r [ mid ] ; q u i c k s o r t ( arr , i , r);
swap ( a r r [ mid ] , a r r [ l ] ) ; }
int i = l + 1 , j = r ;

4.3 Longest Increasing Subsequence (LIS)


O(nlogn). M [i] representa o índice do menor elemento tal que existe uma sequência de tamanho i que termina nele.

#define MAXN 100009 m = ( l+h ) / 2 ;


i f ( a r r [M[m] ] < a r r [ i ] ) l = m; //
i n t LIS ( i n t ∗ a r r , i n t n ) { estritamente crescente
i n t M[ n + 1 ] , L=1 , l , h , m; // i f ( a r r [M[m]]<= a r r [ i ] ) l = m; //
M[ 1 ] = 0 ; crescente
f o r ( i n t i =1; i <n ; i ++){ e l s e h = m;
i f ( a r r [ i ]< a r r [M[ 1 ] ] ) { // e s t r i t a m e n t e }
crescente i f ( h>L ) L=h ;
// i f ( a r r [ i ]<= a r r [M[ 1 ] ] ) { // c r e s c e n t e M[ h ] = i ;
M[ 1 ] = i ; continue ; }
} return L ;
l = 1 ; h = L+1; }
while ( h>l +1){
26
CAPÍTULO 4. PARADIGMAS 27

4.4 Maximum Sum Increasing Subsequence


O(nlogn). M IS[k] é o maior soma de uma subsequência crescente que termina em k. rank[i] é o valor do índice de arr[i]
quando ordenada. A[i] = M IS[k], rank[k] = i.

#include <v e c t o r > e l s e return a r r [ a ] < a r r [ b ] ;


#include <a l g o r i t h m > }
#include <c s t r i n g >
#define MAXN 100009 i n t MSIS ( ) {
using namespace s t d ; f o r ( i n t i =1; i <=N; i ++) i n v r a n k [ i ] = i ;
s o r t ( i n v r a n k +1 , i n v r a n k+1+N, &rankcomp ) ;
i n t comp ( i n t a , i n t b ) { f o r ( i n t i =1; i <=N; i ++) rank [ i n v r a n k [ i ] ] = i ;
return max( a , b ) ; memset(&A, 0 , s i z e o f A) ;
} FenwickTree f t (N) ;
f o r ( i n t i =1 , j ; i <=N; i ++){
c l a s s FenwickTree { . . . }; j = rank [ i ] ;
A[ j ] = a r r [ i ] + f t . r s q ( j −1) ;
i n t a r r [MAXN] , A[MAXN] ; f t . update ( j , A[ j ] ) ;
i n t rank [MAXN] , i n v r a n k [MAXN] , N; }
return f t . r s q (N) ;
bool rankcomp ( i n t a , i n t b ) { }
// i f ( a r r [ a ] == a r r [ b ] ) r e t u r n a<b ; // c r e s c e n t e
i f ( a r r [ a ] == a r r [ b ] ) return a>b ; //
estritamente crescente

4.5 Problema dos Pares mais Próximos


Algoritmo O(nlogn) para achar os pares mais próximos segundo a distância euclidiana em uma array de pontos no espaço.

#include <c s t d i o > double dr = d i s t ( pr . f i r s t , pr . s e c o n d ) ;


#include <a l g o r i t h m > double d l = d i s t ( p l . f i r s t , p l . s e c o n d ) ;
#include <i o s t r e a m > double d = min ( dl , dr ) ;
#include <cmath> double midx = 0 . 5 ∗ ( p o i n t s [ mid ] . x + p o i n t s [ mid
#include <s e t > +1]. x) ;
#define EPS 1 e−9 i n t k l =0 , k r ;
#define INF 1 e+9 f o r ( i n t i=a ; i <=mid ; i ++){
#define MAXN 100009 i f ( p o i n t s [ i ] . x >= midx − d − EPS) aux [ k l ++]
using namespace s t d ; = points [ i ] ;
}
struct p o i n t { kr = k l ;
double x , y ; f o r ( i n t i=mid +1; i <=b ; i ++){
point () { x = y = 0 . 0 ; } i f ( p o i n t s [ i ] . x <= midx + d + EPS) aux [ k r++]
p o i n t ( double _x , double _y) : x (_x) , y (_y) {} = points [ i ] ;
}; e l s e break ;
}
double d i s t ( p o i n t p1 , p o i n t p2 ) { s o r t ( aux , aux+k l , &compy ) ;
return hypot ( p1 . x − p2 . x , p1 . y − p2 . y ) ; s o r t ( aux+k l , aux+kr , &compy ) ;
} f o r ( i n t i =0 , k=k l ; i <k l ; i ++){
f o r ( i n t j=k ; j <k r ; j ++){
typedef p a i r <p o i n t , p o i n t > pp ; i f ( aux [ i ] . y − aux [ j ] . y > d + EPS) k=j
+1;
bool compx ( p o i n t a , p o i n t b ) { e l s e i f ( aux [ j ] . y − aux [ i ] . y > d + EPS)
i f ( f a b s ( a . x − b . x )<EPS) return a . y < b . y ; break ;
e l s e return a . x < b . x ; e l s e i f ( d i s t ( ans . f i r s t , ans . s e c o n d ) >
} d i s t ( aux [ i ] , aux [ j ] ) ) ans =
make_pair ( aux [ i ] , aux [ j ] ) ;
bool compy ( p o i n t a , p o i n t b ) { }
i f ( f a b s ( a . y − b . y )<EPS) return a . x < b . x ; }
e l s e return a . y < b . y ; i f ( dr < d i s t ( ans . f i r s t , ans . s e c o n d ) ) ans = pr ;
} i f ( d l < d i s t ( ans . f i r s t , ans . s e c o n d ) ) ans = p l ;
return ans ;
pp c l o s e s t P a i r ( p o i n t ∗ p o i n t s , p o i n t ∗ aux , i n t a , i n t }
b) {
pp pl , pr , ans = make_pair ( p o i n t (−INF , 0 ) , p o i n t pp c l o s e s t P a i r ( p o i n t ∗ p o i n t s , i n t n ) {
( 0 , INF ) ) ; p o i n t aux [ n ] ;
i f ( a == b ) return ans ; s o r t ( p o i n t s , p o i n t s+n , &compx ) ;
i n t mid = ( a+b ) / 2 ; return c l o s e s t P a i r ( p o i n t s , aux , 0 , n−1) ;
p l = c l o s e s t P a i r ( p o i n t s , aux , a , mid ) ; }
pr = c l o s e s t P a i r ( p o i n t s , aux , mid+1 , b ) ;
CAPÍTULO 4. PARADIGMAS 28

4.6 Otimização de Dois Ponteiros


Reduz a complexidade de O(n2 k) para O(nk) de PD’s da seguinte forma (e outras variantes):

dp[i][j] = 1 + min (max(dp[k − 1][j − 1], dp[i − k][j])), caso base : dp[0][j], dp[i][0] (4.1)
1≤k≤i

• A[i][j] = k ótimo que minimiza dp[i][j].


• É necessário que dp[i][j] seja crescente em i: dp[i][j] ≤ dp[i + 1][j].
• Este exemplo é o problema dos ovos e dos prédios.

#include <a l g o r i t h m > f o r ( i n t j =1; j<=K; j ++) {


using namespace s t d ; dp [ i ] [ j ] = INF ;
#define MAXN 1009 f o r ( i n t k=A[ i − 1 ] [ j ] ; k<=i ; k++) {
#define MAXK 19 i n t c u r = 1 + max( dp [ k − 1 ] [ j − 1 ] , dp [ i −k ] [
#define INF (1<<30) j ]) ;
i f ( dp [ i ] [ j ] > c u r ) {
i n t dp [MAXN] [MAXK] , A[MAXN] [MAXK] , N, K; dp [ i ] [ j ] = c u r ;
A[ i ] [ j ] = k ;
void t w o p o i n t e r ( ) { }
f o r ( i n t i =0; i <=N; i ++) dp [ i ] [ 0 ] = INF ; i f ( dp [ k − 1 ] [ j −1] > dp [ i −k ] [ j ] ) break ;
f o r ( i n t j =0; j<=K; j ++) dp [ 0 ] [ j ] = 0 , A [ 0 ] [ j ] = }
1; }
dp [ 0 ] [ 0 ] = 0 ; }
f o r ( i n t i =1; i <=N; i ++) { }

4.7 Otimização de Convex Hull Trick


Reduz a complexidade de O(n2 k) para O(nklogn) de uma PD da seguinte forma (e outras variantes):

dp[i][j] = min (A[k] ∗ x[i] + dp[k][j − 1]), caso base : dp[0][j], dp[i][0] (4.2)
0≤k<i

É necessário que A seja decrescente: A[i] ≥ A[i + 1].

#include <v e c t o r > f o r ( i n t i =0; i <=N; i ++) dp [ i ] [ 0 ] = 0 ;


#define INF (1<<30) CHTrick c h t ( f a l s e ) ;
#define MAXN 1009 f o r ( i n t j =1; j<=K; j ++){
using namespace s t d ; dp [ 0 ] [ j ] = 0 ;
cht . c l e a r ( ) ;
typedef long long l l ; f o r ( i n t i =1; i <=N; i ++){
c l a s s CHTrick { . . . } ; c h t . push (A[ i − 1 ] , dp [ i − 1 ] [ j −1]) ;
dp [ i ] [ j ] = c h t . query ( x [ i ] ) ;
l l x [MAXN] , A[MAXN] , dp [MAXN] [MAXN] ; }
i n t N, K; }
}
void s o l v e ( ) {

4.8 Otimização de Slope Trick


Reduz a complexidade de O(nS 2 ) para O(nlogn) da seguinte PD, onde f [i] = minj (dp[i][j]) e opt[i] = j que otimiza f [i]:

dp[i][j] = min(dp[i − 1][k] + |a[i] − k|), caso base : dp[0][j] = max(0, a[i] − j) (4.3)
k≤j

#include <queue> pq . push ( a [ 0 ] ) ;


#include <a l g o r i t h m > f o r ( i n t i =1; i <N; i ++){
using namespace s t d ; pq . push ( a [ i ] ) ;
#define MAXN 3009 f [ i ] = f [ i −1] + abs ( a [ i ] − pq . top ( ) ) ;
i f ( a [ i ] < pq . top ( ) ) {
typedef long long l l ; pq . pop ( ) ; pq . push ( a [ i ] ) ;
i n t N; }
l l a [MAXN] , f [MAXN] , opt [MAXN] ; opt [ i ] = pq . top ( ) ;
}
ll slope () { return f [ N− 1 ] ;
p r i o r i t y _ q u e u e <l l > pq ; }
opt [ 0 ] = a [ 0 ] ; f [ 0 ] = 0 ;
CAPÍTULO 4. PARADIGMAS 29

4.9 Otimização de Divisão e Conquista


Reduz a complexidade de O(n2 k) para O(nklogn) de PD’s das seguintes formas (e outras variantes):

dp[i][j] = min (dp[k][j − 1] + C[k][i]), caso base : dp[0][j], dp[i][0] (4.4)


0≤k<i

• C[i][k] = custo que só depende de i e de k.


• A[i][j] = k ótimo que minimiza dp[i][j].

É necessário que A seja crescente ao longo de cada coluna: A[i][j] ≤ A[i + 1][j].

#include <c s t d i o > ans = dp [ k ] [ j −1] + C [ k ] [ i ] ;


#include <a l g o r i t h m > }
using namespace s t d ; }
#define MAXN 1009 dp [ i ] [ j ] = ans ;
#define INF ( 1 << 3 0 ) c a l c u l a t e d p ( min_i , i −1 , j , min_k , opt ) ;
c a l c u l a t e d p ( i +1 , max_i , j , opt , max_k) ;
i n t dp [MAXN] [MAXN] , C [MAXN] [MAXN] , N, K; }

void c a l c u l a t e d p ( i n t min_i , i n t max_i , i n t j , i n t void s o l v e ( ) {


min_k , i n t max_k) { f o r ( i n t i =0; i <=N; i ++) dp [ i ] [ 0 ] = 0 ;
i f ( min_i > max_i ) return ; f o r ( i n t j =0; j<=K; j ++) dp [ 0 ] [ j ] = 0 ;
i n t i = ( min_i + max_i ) / 2 ; f o r ( i n t j =1; j<=K; j ++){
i n t ans = INF , opt ; c a l c u l a t e d p ( 1 , N, j , 0 , N−1) ;
f o r ( i n t k=min_k ; k<=min (max_k , i −1) ; k++){ }
i f ( ans > dp [ k ] [ j −1] + C [ k ] [ i ] ) { }
opt = k ;

4.10 Otimização de Knuth


Reduz a complexidade de O(n3 ) para O(n2 ) de PD’s das seguintes formas (e outras variantes):

dp[i][j] = C[i][j] + min (dp[i][k] + dp[k][j]), caso base : dp[i][j], j − i < S (4.5)
i<k<j

dp[i][j] = min (dp[i][k] + C[i][k]), caso base : dp[i][j], j − i < S (4.6)


i<k<j

• S é uma constante definida, normalmente 1 (caso base dp[i][i]).


• C[i][j] = custo que só depende de i e de j.
• A[i][j] = k ótimo que minimiza dp[i][j].
É necessário que se satisfaçam as seguintes condições:

• Desigualdade quadrangular sobre C: C[a][c] + C[b][d] ≤ C[a][d] + C[b][c], a ≤ b ≤ c ≤ d.


• Monotonicidade sobre C: C[b][c] ≤ C[a][d], a ≤ b ≤ c ≤ d.
Ou a seguinte condição:
• A crescente nas linhas e nas colunas: A[i][j − 1] ≤ A[i][j] ≤ A[i + 1][j].

#include <c s t d i o > A[ i ] [ j ] = i ;


#define MAXN 1009 continue ;
#define INF ( 1LL << 6 0 ) }
dp [ i ] [ j ] = INF ;
typedef long long l l ; f o r ( i n t k = A[ i ] [ j − 1 ] ; k <= A[ i + 1 ] [ j ] ; k++)
{
l l dp [MAXN] [MAXN] , C [MAXN] [MAXN] ; c u r = C [ i ] [ j ] + dp [ i ] [ k ] + dp [ k ] [ j ] ;
i n t A[MAXN] [MAXN] , N, S ; i f ( dp [ i ] [ j ] > c u r ) {
dp [ i ] [ j ] = c u r ;
void knuth ( ) { A[ i ] [ j ] = k ;
l l cur ; }
f o r ( i n t s = 0 ; s < N; s++){ }
f o r ( i n t i =0 , j ; i + s<N; i ++){ }
j = i + s; }
i f ( s < S ) { // Caso b a s e }
dp [ i ] [ j ] = 0 ;
Capítulo 5

Grafos

5.1 DFS e BFS


#include <c s t d i o > f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){
#include <s t a c k > v = adjList [u ] [ i ] ;
#include <queue> if (! vis [ v ]) {
using namespace s t d ; v i s [ v ] = true ;
#define MAXN 1009 s . push ( v ) ;
}
i n t v i s [MAXN] ; }
v e c t o r <int> a d j L i s t [MAXN] ; }
}
void d f s ( i n t u ) {
v i s [ u]= true ; void b f s ( ) {
/∗ a t i v i d a d e s n e s t e no ∗/ memset(& v i s , f a l s e , s i z e o f v i s ) ;
int v ; queue<int> q ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){ q . push ( r o o t ) ;
v = adjList [u ] [ i ] ; int u , v ;
if ( ! vis [ v ] ) dfs (v) ; while ( ! q . empty ( ) ) {
} u = q . top ( ) ;
} q . pop ( ) ;
/∗ a t i v i d a d e s n e s t e no ∗/
void d f s s t a c k ( ) { f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){
memset(& v i s , f a l s e , s i z e o f v i s ) ; v = adjList [u ] [ i ] ;
s t a c k <int> s ; if (! vis [ v ]) {
s . push ( r o o t ) ; v i s [ v ] = true ;
int u , v ; q . push ( v ) ;
while ( ! s . empty ( ) ) { }
u = s . top ( ) ; }
s . pop ( ) ; }
/∗ a t i v i d a d e s n e s t e no ∗/ }

5.2 DFS Spanning Tree


#include <c s t d i o > i f ( v i s [ v ] == UNVISITED) {
#include <v e c t o r > p r i n t f ( " ␣ Tree ␣ Edge ␣(%d , ␣%d ) \n" , u , v ) ;
using namespace s t d ; p a r e n t [ v ] = u ; // p a r e n t o f t h i s c h i l d r e n
#define MAXN 1009 i s me
#define UNVISITED −1 graphCheck ( v ) ;
#define EXPLORED −2 }
#define VISITED −3 e l s e i f ( v i s [ v ] == EXPLORED) {
p r i n t f ( " ␣ Back ␣Edge ␣(%d , ␣%d ) ␣ ( C y c l e ) \n" , u ,
i n t v i s [MAXN] , p a r e n t [MAXN] ; v) ;
v e c t o r <int> a d j L i s t [MAXN] ; }
e l s e i f ( v i s [ v ] == VISITED )
void graphCheck ( i n t u ) { // DFS f o r c h e c k i n g g raph p r i n t f ( " ␣ Forward / C r o s s ␣ Edge ␣(%d , ␣%d ) \n" , u ,
edge p r o p e r t i e s v) ;
v i s [ u ] = EXPLORED; }
for ( int j = 0 , v ; j < ( int ) a d j L i s t [ u ] . s i z e ( ) ; j v i s [ u ] = VISITED ;
++) { }
v = adjList [u ] [ j ] ;

30
CAPÍTULO 5. GRAFOS 31

5.3 Pontos de articulação e Pontes


#include <c s t d i o > }
#include <v e c t o r > e l s e i f ( v != p a r e n t [ u ] )
#include <a l g o r i t h m > low [ u ] = min ( low [ u ] , num [ v ] ) ;
#include <c s t r i n g > }
using namespace s t d ; }
#define MAXN 1009
#define UNVISITED −1 i n t main ( ) {
counter = 0;
i n t num [MAXN] , N, low [MAXN] , p a r e n t [MAXN] , c o u n t e r , memset(&num , UNVISITED , s i z e o f num) ;
r o o t C h i l d r e n , a r t i c u l a t i o n V e r t e x [MAXN] , r o o t ; memset(&low , 0 , s i z e o f low ) ;
v e c t o r <int> a d j L i s t [MAXN] ; memset(& p a r e n t , 0 , s i z e o f p a r e n t ) ;
memset(& a r t i c u l a t i o n V e r t e x , 0 , s i z e o f
void t a r j a n ( i n t u ) { articulationVertex ) ;
low [ u ] = num [ u ] = c o u n t e r ++; p r i n t f ( " B r i d g e s : \ n" ) ;
for ( int j = 0 , v ; j < ( int ) a d j L i s t [ u ] . s i z e ( ) ; j f o r ( i n t i = 0 ; i < N; i ++)
++) { i f (num [ i ] == UNVISITED) {
v = adjList [u ] [ j ] ; root = i ; rootChildren = 0; tarjan ( i ) ;
i f (num [ v ] == UNVISITED) { articulationVertex [ root ] = ( rootChildren >
parent [ v ] = u ; 1) ;
i f ( u == r o o t ) r o o t C h i l d r e n ++; } // s p e c i a l c a s e
tarjan (v) ; p r i n t f ( " A r t i c u l a t i o n ␣ P o i n t s : \ n" ) ;
i f ( low [ v ] >= num [ u ] ) a r t i c u l a t i o n V e r t e x [ u ] f o r ( i n t i = 0 ; i < N; i ++)
= true ; if ( articulationVertex [ i ])
i f ( low [ v ] > num [ u ] ) p r i n t f ( " ␣Edge ␣(%d , ␣%d ) p r i n t f ( " ␣ V er te x ␣%d\n" , i ) ;
␣ i s ␣ a ␣ b r i d g e \n" , u , v ) ; return 0 ;
low [ u ] = min ( low [ u ] , low [ v ] ) ; }

5.4 Ordenação Topológica


Inicializar vis como false. toposort guarda a ordenação na ordem inversa!

#include <c s t d i o > void t s ( i n t u ) {


#include <v e c t o r > v i s [ u ] = true ;
using namespace s t d ; for ( int j = 0 , v ; j < ( int ) a d j L i s t [ u ] . s i z e ( ) ; j
#define MAXN 1009 ++) {
v = adjList [u ] [ j ] ;
i n t v i s [MAXN] ; if (! vis [ v ]) ts (v) ;
v e c t o r <int> a d j L i s t [MAXN] ; }
v e c t o r <int> t o p o s o r t ; //Ordem r e v e r s a ! t o p o s o r t . push_back ( u ) ;
}

5.5 Componentes Fortemente Conexos: Algoritmo de Tarjan


#include <c s t d i o > i f ( v i s [ v ] ) low [ u ] = min ( low [ u ] , low [ v ] ) ;
#include <v e c t o r > }
#include <s t a c k > i f ( low [ u ] == num [ u ] ) {
#include <a l g o r i t h m > while ( true ) {
#include <c s t r i n g > v = S . top ( ) ; S . pop ( ) ; v i s [ v ] = 0 ;
using namespace s t d ; component [ v ] = numSCC ;
#define MAXN 100009 i f ( u == v ) break ;
#define UNVISITED −1 }
numSCC++;
i n t num [MAXN] , v i s [MAXN] , component [MAXN] , N, M, low }
[MAXN] , c o u n t e r , r o o t , numSCC ; }
s t a c k <int> S ;
v e c t o r <int> a d j L i s t [MAXN] ; void t a r j a n ( ) {
c o u n t e r = numSCC = 0 ;
void d f s ( i n t u ) { memset(&num , UNVISITED , s i z e o f num) ;
low [ u ] = num [ u ] = c o u n t e r ++; memset(& v i s , 0 , s i z e o f v i s ) ;
S . push ( u ) ; memset(&low , 0 , s i z e o f low ) ;
vis [u ] = 1; f o r ( i n t i = 0 ; i < N; i ++){
int v ; i f (num [ i ] == UNVISITED)
f o r ( i n t j = 0 ; j < ( i n t ) a d j L i s t [ u ] . s i z e ( ) ; j ++) dfs ( i ) ;
{ }
v = adjList [u ] [ j ] ; }
i f (num [ v ] == UNVISITED) d f s ( v ) ;
CAPÍTULO 5. GRAFOS 32

5.6 Componentes Fortemente Conexos: Algoritmo de Kosaraju


#include <c s t d i o > component [ u ] = p a r e n t ;
#include <v e c t o r > f o r ( i n t i =0 , v ; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){
#include <c s t r i n g > v = adjList [u ] [ i ] ;
#define MAXN 100009 i f ( ! num [ v ] ) d f s ( v ) ;
using namespace s t d ; }
}
v e c t o r <int> a d j L i s t [MAXN] , r e v A d j L i s t [MAXN] ,
toposort ; void k o s a r a j u ( ) {
bool num [MAXN] ; memset(&num , f a l s e , s i z e o f num) ;
i n t component [MAXN] , p a r e n t = 0 , N, M, numSCC ; f o r ( i n t i =0; i <N; i ++) {
i f ( ! num [ i ] ) r e v d f s ( i ) ;
void r e v d f s ( i n t u ) { }
num [ u ] = true ; memset(&num , f a l s e , s i z e o f num) ;
f o r ( i n t i =0 , v ; i <( i n t ) r e v A d j L i s t [ u ] . s i z e ( ) ; i numSCC = 0 ;
++){ f o r ( i n t i=N−1; i >=0; i −−){
v = revAdjList [ u ] [ i ] ; i f ( ! num [ t o p o s o r t [ i ] ] ) {
i f ( ! num [ v ] ) r e v d f s ( v ) ; parent = toposort [ i ] ;
} dfs ( toposort [ i ] ) ;
t o p o s o r t . push_back ( u ) ; numSCC++;
} }
}
void d f s ( i n t u ) { }
num [ u ] = true ;

5.7 Caminho mínimo: Algoritmo de Dijkstra


Caminho mínimo entre dois nós. Funciona para arestas negativas sem ciclos negativos. O(V logV + E).

#include <c s t d i o > nodes . i n s e r t ( i i ( 0 , s ) ) ;


#include <s e t > while ( ! nodes . empty ( ) ) {
#include <v e c t o r > i n t u = nodes . b e g i n ( )−>s e c o n d ;
#include <c s t r i n g > nodes . e r a s e ( nodes . b e g i n ( ) ) ;
#include <i o s t r e a m > f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){
using namespace s t d ; int v = a d j L i s t [ u ] [ i ] . second ;
#define MAXN 100009 int w = a d j L i s t [ u ] [ i ] . f i r s t ;
#define INF (1<<30) i f ( d i s t [ v ] > d i s t [ u ] + w) {
i f ( d i s t [ v ] < INF ) {
typedef p a i r <int , int> i i ; nodes . e r a s e ( i i ( d i s t [ v ] , v ) ) ;
v e c t o r <i i > a d j L i s t [MAXN] ; }
i n t d i s t [MAXN] , n , m; d i s t [ v ] = d i s t [ u ] + w;
nodes . i n s e r t ( i i ( d i s t [ v ] , v ) ) ;
int d i j k s t r a ( int s , int t ) }
{ }
f o r ( i n t i =1; i <=n ; i ++) d i s t [ i ] = INF ; }
d i s t [ s ]=0; return d i s t [ t ] ;
s e t <p a i r <int , int> > nodes ; }

5.8 Caminho mínimo: Algoritmo de Floyd-Warshall


Caminho mínimo em O(V 3 ). Muito rápido de codar, pode calcular caminho mínimo para ir e voltar de cada nó.

#include <c s t i d i o > f o r ( i n t k = 0 ; k < N; k++)


#define MAXN 409 f o r ( i n t i = 0 ; i < N; i ++)
f o r ( i n t j = 0 ; j < N; j ++)
i n t adjMat [MAXN] [MAXN] , N; adjMat [ i ] [ j ] = min ( adjMat [ i ] [ j ] ,
adjMat [ i ] [ k ] + adjMat [ k ] [ j ] ) ;
void f l o y d w a r s h a l l ( ) { }
CAPÍTULO 5. GRAFOS 33

5.9 Caminho mínimo: Algoritmo de Bellman-Ford


Caminho mínimo em grafos com ciclo negativo. O(V E).

#include <c s t d i o > f o r ( i n t i = 0 , v , w ; i < N; i ++){


#include <v e c t o r > f o r ( i n t u = 0 ; u < N; u++) {
#include <c s t r i n g > for ( int j = 0 ; j < ( int ) a d j L i s t [ u ] . s i z e ( ) ;
#include <i o s t r e a m > j ++) {
#define MAXN 1009 v = adjList [u ] [ j ] . f i r s t ;
using namespace s t d ; w = a d j L i s t [ u ] [ j ] . second ;
i f ( i==N−1 && d i s t [ v ] > d i s t [ u ] + w)
i n t d i s t [MAXN] , N; h a s N e g a t i v e W e i g h t C y c l e = true ;
typedef p a i r <int , int> i i ; e l s e d i s t [ v ] = min ( d i s t [ v ] , d i s t [ u ] + w)
v e c t o r <i i > a d j L i s t [MAXN] ; ;
}
int bellmanford ( int s , int t ) }
memset(& d i s t , 1<<20, s i z e o f d i s t ) ; }
dist [ s ] = 0; return d i s t [ t ] ;
bool h a s N e g a t i v e W e i g h t C y c l e = f a l s e ; }

5.10 Caminho mínimo: Shortest Path Faster Algorithm (SPFA)


Caminho mínimo em grafos com ciclo negativo. W orst case O(V E), caso médio igual a dijkstra.

#include <queue> i n q [ s ] = true ;


#include <v e c t o r > while ( ! q . empty ( ) ) {
#include <c s t r i n g > i n t u = q . f r o n t ( ) ; q . pop ( ) ;
#include <i o s t r e a m > inq [ u ] = false ;
using namespace s t d ; for ( int i = 0 ; i < ( int ) a d j L i s t [ u ] . s i z e ( ) ; i
#define MAXN 100009 ++) {
#define INF (1<<30) int v = a d j L i s t [ u ] [ i ] . second ;
int w = a d j L i s t [ u ] [ i ] . f i r s t ;
typedef p a i r <int , int> i i ; if ( dist [u] + w < dist [v ]) {
v e c t o r <i i > a d j L i s t [MAXN] ; d i s t [ v ] = d i s t [ u ] + w;
i n t d i s t [MAXN] , n , m; i f ( ! inq [ v ] ) {
bool i n q [MAXN] ; q . push ( v ) ;
i n q [ v ] = true ;
int s p f a ( int s , int t ) { }
f o r ( i n t i =0; i <=n ; i ++) d i s t [ i ] = INF ; }
memset(& inq , f a l s e , s i z e o f i n q ) ; }
queue<int> q ; }
q . push ( s ) ; return d i s t [ t ] ;
dist [ s ] = 0; }

5.11 Árvore Geradora Mínima: Algoritmo de Kruskal


O(ElogV ).

#include <c s t d i o > ll kruskal () {


#include <v e c t o r > l l cost = 0;
#include <a l g o r i t h m > UnionFind UF(N) ;
using namespace s t d ; p a i r <int , i i > edge ;
s o r t ( e d g e L i s t . b e g i n ( ) , e d g e L i s t . end ( ) ) ;
c l a s s UnionFind { f o r ( i n t i = 0 ; i < M; i ++) {
... edge = e d g e L i s t [ i ] ;
}; i f ( ! UF . i s S a m e S e t ( edge . s e c o n d . f i r s t , edge .
second . second ) ) {
typedef p a i r <int , int> i i ; c o s t += edge . f i r s t ;
typedef long long l l ; UF . u n i o n S e t ( edge . s e c o n d . f i r s t , edge . s e c o n d .
second ) ;
i n t N, M; }
v e c t o r < p a i r <l l , i i > > e d g e L i s t ; // ( w e i g h t , two }
v e r t i c e s ) of the edge return c o s t ;
}
CAPÍTULO 5. GRAFOS 34

5.12 Árvore Geradora Mínima: Algoritmo de Prim


O(ElogE).

#include <v e c t o r > v = adjList [ 0 ] [ j ] ;


#include <queue> pq . push ( i i (−v . second , −v . f i r s t ) ) ;
#include <c s t r i n g > }
#define MAXN 10009 while ( ! pq . empty ( ) ) {
using namespace s t d ; f r o n t = pq . top ( ) ; pq . pop ( ) ;
u = −f r o n t . s e c o n d ; w = −f r o n t . f i r s t ;
typedef long long l l ; i f ( ! taken [ u ] ) {
typedef p a i r <int , int> i i ; c o s t += ( l l )w ; t a k e n [ u ] = true ;
v e c t o r <i i > a d j L i s t [MAXN] ; for ( int j = 0 ; j < ( int ) a d j L i s t [ u ] . s i z e ( ) ;
i n t N, M; j ++) {
v = adjList [u ] [ j ] ;
l l prim ( ) { i f ( ! t a k e n [ v . f i r s t ] ) pq . push ( i i (−v .
bool t a k e n [MAXN] ; second , −v . f i r s t ) ) ;
memset(& taken , f a l s e , s i z e o f t a k e n ) ; }
t a k e n [ 0 ] = true ; }
p r i o r i t y _ q u e u e <i i > pq ; }
i i v , f r o n t ; int u , w; l l c o s t = 0 ; return c o s t ;
f o r ( i n t j = 0 ; j < ( i n t ) a d j L i s t [ 0 ] . s i z e ( ) ; j ++) }
{

5.13 2-SAT
twosat() retorna se existe configuração ou não. N é o dobro do número de variáveis. Para 0 ≤ i < N/2, value[i] = xi e
value[i + N/2] =!xi . O(N + M ).

#include <v e c t o r > i f ( v a l u e [ v ] == 0 && k == 1 ) return f a l s e ;


#include <s t a c k > i f ( v a l u e [ v ] == −1 && ( component [ u ] ==
#include <s e t > component [ v ]
#include <a l g o r i t h m > | | k == 1 ) && ! f f i l l ( v , k ) ) return f a l s e ;
#include <c s t r i n g > }
using namespace s t d ; return true ;
#define MAXN 400009 }
#define UNVISITED −1
#define EXPLORED −2 bool t w o s a t ( ) {
#define VISITED −3 tarjan () ;
f o r ( i n t i =0; i <N/ 2 ; i ++){
i n t num [MAXN] , v i s [MAXN] , component [MAXN] , low [MAXN C [ i ] . c l e a r ( ) ; adjComp [ i ] . c l e a r ( ) ;
]; i f ( component [ i ]==component [ i+N/ 2 ] ) return
i n t v a l u e [MAXN] , N, M, c o u n t e r , r o o t , numSCC ; false ;
s t a c k <int> S ; }
v e c t o r <int> a d j L i s t [MAXN] , t o p o s o r t , C [MAXN] ; f o r ( i n t u=0 , v ; u<N; u++){
s e t <int> adjComp [MAXN] ; C [ component [ u ] ] . push_back ( u ) ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){
void d f s ( i n t u ) { . . . } v = adjList [u ] [ i ] ;
i f ( component [ u ] != component [ v ] )
void t a r j a n ( ) { . . . } adjComp [ component [ u ] ] . i n s e r t ( component [ v
]) ;
void t s ( i n t u ) { }
v i s [ u ] = VISITED ; }
s e t <int > : : i t e r a t o r i t ; memset(& v i s , UNVISITED , s i z e o f v i s ) ;
f o r ( i t = adjComp [ u ] . b e g i n ( ) ; i t !=adjComp [ u ] . end ( ) toposort . clear () ;
; i t ++){ f o r ( i n t i =0; i <numSCC ; i ++){
i f ( v i s [ ∗ i t ] == UNVISITED) d f s ( ∗ i t ) ; i f ( v i s [ i ] == UNVISITED) t s ( i ) ;
} }
t o p o s o r t . push_back ( u ) ; memset(& v a l u e , −1, s i z e o f v a l u e ) ;
} f o r ( i n t i =0 , c , u ; i <( i n t ) t o p o s o r t . s i z e ( ) ; i ++){
c = toposort [ i ] ;
bool f f i l l ( i n t u , i n t k ) { f o r ( i n t j =0; j <( i n t )C [ c ] . s i z e ( ) ; j ++){
value [ u ] = k ; u = C[ c ] [ j ] ;
i n t v = ( u>=N/2 ? u−N/2 : u+N/ 2 ) ; i f ( v a l u e [ u ] == −1 && ! f f i l l ( u , 1 ) )
i f ( v a l u e [ v ] == v a l u e [ u ] ) return f a l s e ; return f a l s e ;
i f ( v a l u e [ v ] == −1 && ! f f i l l ( v , 1−k ) ) return }
false ; }
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++){ return true ;
v = adjList [u ] [ i ] ; }
CAPÍTULO 5. GRAFOS 35

5.14 Fluxo Máximo: Algoritmo de Edmonds-Karp


Fluxo máximo de s a t. O(V E 2 ). Usar add (precisa adicionar ida e volta na lista de adjacência).

#include <queue> return f ;


#include <c s t r i n g > }
#define INF (1<<30) bool b f s ( i n t s , i n t t ) {
#define MAXN 103000 int u , v ;
#define MAXM 900000 memset(& d i s t , −1, s i z e o f d i s t ) ;
using namespace s t d ; dist [ s ] = 0;
queue<int> q ; q . push ( s ) ;
i n t N, M, ned , prv [MAXN] , f i r s t [MAXN] ; memset(&prv , −1, s i z e o f prv ) ;
i n t cap [MAXM] , t o [MAXM] , nxt [MAXM] , d i s t [MAXN] ; while ( ! q . empty ( ) ) {
u = q . f r o n t ( ) ; q . pop ( ) ;
void i n i t ( ) { i f ( u == t ) break ;
memset ( f i r s t , −1, s i z e o f f i r s t ) ; f o r ( i n t e = f i r s t [ u ] ; e != −1; e = nxt [ e ] ) {
ned = 0 ; v = to [ e ] ;
} i f ( d i s t [ v ] < 0 && cap [ e ] > 0 ) {
void add ( i n t u , i n t v , i n t f ) { dist [ v ] = dist [ u ] + 1;
t o [ ned ] = v , cap [ ned ] = f ; q . push ( v ) ;
nxt [ ned ] = f i r s t [ u ] ; prv [ v ] = e ;
f i r s t [ u ] = ned++; }
t o [ ned ] = u , cap [ ned ] = 0 ; }
nxt [ ned ] = f i r s t [ v ] ; }
f i r s t [ v ] = ned++; return d i s t [ t ] >= 0 ;
} }
i n t edmondskarp ( i n t s , i n t t ) {
i n t augment ( i n t v , i n t minEdge , i n t s ) { int r e s u l t = 0 ;
i n t e = prv [ v ] ; while ( b f s ( s , t ) ) {
i f ( e == −1) return minEdge ; r e s u l t += augment ( t , INF , s ) ;
i n t f = augment ( t o [ e ^ 1 ] , min ( minEdge , cap [ e ] ) , s ) }
; return r e s u l t ;
cap [ e ] −= f ; }
cap [ e ^ 1 ] += f ;

5.15 Fluxo Máximo: Algoritmo de Dinic


Fluxo máximo de s a t. O(V 2 E). Usar add (precisa adicionar ida e volta na lista de adjacência).

#include <queue> cap [ e ^ 1 ] += d f ;


#include <c s t r i n g > return d f ;
#define INF (1<<30) }
#define MAXN 103000 }
#define MAXM 900000 }
using namespace s t d ; return 0 ;
}
i n t N, M, ned , f i r s t [MAXN] ; bool b f s ( i n t s , i n t t ) {
i n t cap [MAXM] , t o [MAXM] , nxt [MAXM] , d i s t [MAXN] ; int u , v ;
memset(& d i s t , −1, s i z e o f d i s t ) ;
void i n i t ( ) { dist [ s ] = 0;
memset ( f i r s t , −1, s i z e o f f i r s t ) ; queue<int> q ; q . push ( s ) ;
ned = 0 ; while ( ! q . empty ( ) ) {
} u = q . f r o n t ( ) ; q . pop ( ) ;
void add ( i n t u , i n t v , i n t f ) { f o r ( i n t e = f i r s t [ u ] ; e != −1; e = nxt [ e ] ) {
t o [ ned ] = v , cap [ ned ] = f ; v = to [ e ] ;
nxt [ ned ] = f i r s t [ u ] ; i f ( d i s t [ v ] < 0 && cap [ e ] > 0 ) {
f i r s t [ u ] = ned++; dist [ v ] = dist [ u ] + 1;
t o [ ned ] = u , cap [ ned ] = 0 ; q . push ( v ) ;
nxt [ ned ] = f i r s t [ v ] ; }
f i r s t [ v ] = ned++; }
} }
return d i s t [ t ] >= 0 ;
int d f s ( int u , int f , int s , int t ) { }
i f ( u == t ) return f ; int d i n i c ( int s , int t ) {
int v , df ; int r e s u l t = 0 , f ;
f o r ( i n t e = f i r s t [ u ] ; e != −1; e = nxt [ e ] ) { while ( b f s ( s , t ) ) {
v = to [ e ] ; while ( f = d f s ( s , INF , s , t ) ) r e s u l t += f ;
i f ( d i s t [ v ] == d i s t [ u ] + 1 && cap [ e ] > 0 ) { }
d f = d f s ( v , min ( f , cap [ e ] ) , s , t ) ; return r e s u l t ;
i f ( df > 0) { }
cap [ e ] −= d f ;
CAPÍTULO 5. GRAFOS 36

5.16 Maximum Matching: Algoritmo húngaro


Emparelhamento máximo em grafo bipartido em O(V E). Vértices enumerados de 1 a m em U e de 1 a n em V. Mais rápido
de codar do que Hopcroft-Karp.

#include <c s t d i o > pairV [ v ] = u ; pairU [ u ] = v ;


#include <c s t r i n g > return true ;
#include <v e c t o r > }
using namespace s t d ; }
#define MAXN 1009 return f a l s e ;
}
v e c t o r <int> adjU [MAXN] ;
i n t pairU [MAXN] , pairV [MAXN] ; int hungarian ( )
bool v i s [MAXN] ; {
i n t m, n ; memset(&pairU , 0 , s i z e o f pairU ) ;
memset(&pairV , 0 , s i z e o f pairV ) ;
bool d f s ( i n t u ) int r e s u l t = 0 ;
{ f o r ( i n t u = 1 ; u <= m; u++){
v i s [ u ] = true ; memset(& v i s , f a l s e , s i z e o f v i s ) ;
i f ( u == 0 ) return true ; i f ( pairU [ u]==0 && d f s ( u ) )
int v ; r e s u l t ++;
f o r ( i n t i =0; i !=( i n t ) adjU [ u ] . s i z e ( ) ; ++i ) { }
v = adjU [ u ] [ i ] ; return r e s u l t ;
i f ( ! v i s [ pairV [ v ] ] && d f s ( pairV [ v ] ) ) { }

5.17 Maximum Matching: Algoritmo de Hopcroft-Karp



Emparelhamento máximo em grafo bipartido em O( V E). Vértices enumerados de 1 a m em U e de 1 a n em V.

#include <v e c t o r > }


#include <queue> }
#include <c s t d i o > return ( d i s t [ 0 ] != INF ) ;
#include <c s t r i n g > }
#define INF (1<<30)
#define MAXN 1009 bool d f s ( i n t u )
using namespace s t d ; {
i f ( u == 0 ) return true ;
v e c t o r <int> adjU [MAXN] ; int v ;
i n t pairU [MAXN] , pairV [MAXN] , d i s t [MAXN] ; f o r ( i n t i =0; i !=( i n t ) adjU [ u ] . s i z e ( ) ; ++i ) {
i n t m, n ; v = adjU [ u ] [ i ] ;
i f ( d i s t [ pairV [ v ] ] == d i s t [ u ]+1) {
bool b f s ( ) i f ( d f s ( pairV [ v ] ) ) {
{ pairV [ v ] = u ; pairU [ u ] = v ;
queue<int> q ; return true ;
f o r ( i n t u=1; u<=m; u++){ }
i f ( pairU [ u]==0) { }
dist [ u ] = 0; }
q . push ( u ) ; d i s t [ u ] = INF ;
} return f a l s e ;
e l s e d i s t [ u ] = INF ; }
}
d i s t [ 0 ] = INF ; int hopcroftKarp ( )
int u , v ; {
while ( ! q . empty ( ) ) { memset(&pairU , 0 , s i z e o f pairU ) ;
u = q . f r o n t ( ) ; q . pop ( ) ; memset(&pairV , 0 , s i z e o f pairV ) ;
if ( dist [u] < dist [0]) { int r e s u l t = 0 ;
f o r ( i n t i =0; i <( i n t ) adjU [ u ] . s i z e ( ) ; ++i while ( b f s ( ) ) {
) { f o r ( i n t u=1; u<=m; u++){
v = adjU [ u ] [ i ] ; i f ( pairU [ u]==0 && d f s ( u ) )
i f ( d i s t [ pairV [ v ] ] == INF ) { r e s u l t ++;
d i s t [ pairV [ v ] ] = d i s t [ u ] + 1 ; }
q . push ( pairV [ v ] ) ; }
} return r e s u l t ;
} }
CAPÍTULO 5. GRAFOS 37

5.18 Maximum Matching: Algoritmo Blossom


Recebe a matriz de adjacência de um grafo qualquer e preenche o vetor pair com os devidos pares de cada nó. O(n4 ).

#include <c s t d i o > b a s e [ u]= newBase ;


#include <c s t r i n g > i f ( ! inQueue [ u ] ) push ( u ) ;
#define MAXN 79 }
}
i n t n , p a i r [MAXN] , head , t a i l , queue [MAXN] , s t a r t ,
f i n i s h , newBase , p a r e n t [MAXN] , b a s e [MAXN] ; void findAugmentingPath ( ) {
bool adjMat [MAXN] [MAXN] , inQueue [MAXN] , inPath [MAXN int u , v ;
] , i n B l o s s o m [MAXN] ; memset ( inQueue , f a l s e , s i z e o f ( inQueue ) ) ;
memset ( p a r e n t , 0 , s i z e o f ( p a r e n t ) ) ;
void push ( i n t u ) { f o r ( u = 1 ; u <= n ; u++) b a s e [ u]=u ;
queue [ t a i l ++] = u ; head = 1 ; t a i l = 1 ;
inQueue [ u ] = true ; push ( s t a r t ) ;
} finish = 0;
while ( head < t a i l ) {
i n t findCommonAncestor ( i n t u , i n t v ) { u = queue [ head ++];
memset ( inPath , 0 , s i z e o f ( inPath ) ) ; f o r ( v = 1 ; v <= n ; v++)
while ( true ) { i f ( adjMat [ u ] [ v ] && b a s e [ u ] ! = b a s e [ v ] &&
u = base [ u ] ; pair [ u]!= v)
inPath [ u ] = true ; i f ( v == s t a r t | | ( p a i r [ v ] > 0 &&
i f ( u == s t a r t ) break ; parent [ p a i r [ v ] ] > 0) )
u = parent [ pair [ u ] ] ; blossomContract (u , v ) ;
} e l s e i f ( p a r e n t [ v ] == 0 ) {
while ( true ) { parent [ v ] = u ;
v = base [ v ] ; i f ( p a i r [ v ] > 0 ) push ( p a i r [ v ] ) ;
i f ( inPath [ v ] ) break ; e l s e { f i n i s h = v ; return ; }
v = parent [ pair [ v ] ] ; }
} }
return v ; }
}
void augmentPath ( ) {
void r e s e t T r a c e ( i n t u ) { int u , v ,w;
int v ; u = finish ;
while ( b a s e [ u ] != newBase ) { while ( u > 0 ) {
v = pair [ u ] ; v = parent [ u ] ; w = pair [ v ] ;
inBlossom [ base [ u ] ] = 1 ; p a i r [ v ] = u ; p a i r [ u ] = v ; u = w;
inBlossom [ base [ v ] ] = 1 ; }
u = parent [ v ] ; }
i f ( b a s e [ u ] != newBase ) p a r e n t [ u ] = v ;
} void edmondskarpmaxmatch ( ) {
} int u ;
memset ( p a i r , 0 , s i z e o f ( p a i r ) ) ;
void b l o s s o m C o n t r a c t ( i n t u , i n t v ) { f o r ( u = 1 ; u <= n ; u++)
newBase = findCommonAncestor ( u , v ) ; i f ( p a i r [ u ] == 0 )
memset ( inBlossom , 0 , s i z e o f ( i n B l o s s o m ) ) ; {
resetTrace (u) ; start = u;
resetTrace (v) ; findAugmentingPath ( ) ;
i f ( b a s e [ u ] != newBase ) p a r e n t [ u]= v ; i f ( f i n i s h > 0 ) augmentPath ( ) ;
i f ( b a s e [ v ] != newBase ) p a r e n t [ v]= u ; }
f o r ( u=1;u<=n ; u++) }
i f ( inBlossom [ base [ u ] ] ) {

5.19 Corte Mínimo Global: Algoritmo de Stoer-Wagner


Calcula o corte mínimo global em O(V 3 ): dado um grafo representado com matriz de adjacência, calcula o custo mínimo
para desconectar o grafo. Esta implementação modifica o grafo, logo se precisar dele depois deve-se fazer uma cópia.

#include <c s t d i o > i n t mincut ( ) {


#include <v e c t o r > i n t b e s t C o s t = INF ;
#include <c s t r i n g > v e c t o r <int> v [MAXN] ;
using namespace s t d ; f o r ( i n t i =0; i <n ; ++i )
#define MAXN 509 v [ i ] . assign (1 , i ) ;
#define INF (1<<30) i n t w [MAXN] , s e l ;
bool e x i s t [MAXN] , added [MAXN] ;
i n t n , a d j M a t r i x [MAXN] [MAXN] ; memset ( e x i s t , true , s i z e o f e x i s t ) ;
v e c t o r <int> be st C ut ; f o r ( i n t phase =0; phase<n−1; ++phase ) {
memset ( added , f a l s e , s i z e o f added ) ;
CAPÍTULO 5. GRAFOS 38

memset (w, 0 , s i z e o f w) ; f o r ( i n t i =0; i <n ; ++i ) a d j M a t r i x [


f o r ( i n t j =0 , p r e v ; j <n−phase ; ++j ) { p r e v ] [ i ] = a d j M a t r i x [ i ] [ p r e v ] +=
s e l = −1; adjMatrix [ s e l ] [ i ] ;
f o r ( i n t i =0; i <n ; ++i ) { exist [ s e l ] = false ;
i f ( e x i s t [ i ] && ! added [ i ] && ( s e l == }
−1 | | w [ i ] > w [ s e l ] ) ) else {
sel = i ; added [ s e l ] = true ;
} f o r ( i n t i =0; i <n ; ++i ) w [ i ] +=
i f ( j == n−phase −1) { adjMatrix [ s e l ] [ i ] ;
i f (w [ s e l ] < b e s t C o s t ) { prev = s e l ;
bestCost = w[ s e l ] ; }
b es tC u t = v [ s e l ] ; }
} }
v [ p r e v ] . i n s e r t ( v [ p r e v ] . end ( ) , v [ s e l return b e s t C o s t ;
] . b e g i n ( ) , v [ s e l ] . end ( ) ) ; }

5.20 Min Cost Max Flow


O(V E(V logV + E)). Usar função add para adiconar as arestas. K é o fluxo desejado, ao final do algoritmo K retorna quanto
de fluxo não foi possível repassar. Para alguns problemas, pode ser necessário duplicar os nós em nó de entrada e de saída e
colocar uma aresta de capacidade infinita e custo zero entre eles. Ex: problema bidirecionado. Usa dijstra modificado com
função potencial.

#include <c s t d i o > q . erase (q . begin () ) ;


#include <c l i m i t s > f o r ( i n t e = f i r s t [ u ] ; e != −1; e = nxt [ e ] ) {
#include <c s t r i n g > i f ( cap [ e ]<=0) continue ;
#include <queue> v = to [ e ] ;
#include <s e t > l l new_dist = d i s t [ u ] + c o s t [ e ] + pot [ u ]
− pot [ v ] ;
using namespace s t d ; i f ( new_dist < d i s t [ v ] ) {
#define MAXN 103000 q . e r a s e ( make_pair ( d i s t [ v ] , v ) ) ;
#define MAXM 900000 d i s t [ v ] = new_dist ;
#define INF ( 1LL << 6 0 ) prv [ v ] = e ;
typedef long long l l ; q . i n s e r t ( make_pair ( new_dist , v ) ) ;
}
i n t N, M, ned , prv [MAXN] , f i r s t [MAXN] ; }
l l cap [MAXM] , c o s t [MAXM] , t o [MAXM] , nxt [MAXM] , d i s t [ }
MAXN] , pot [MAXN] , K; return prv [ t ]!= −1;
}
void i n i t ( ) {
memset ( f i r s t , −1, s i z e o f f i r s t ) ; l l augment ( i n t s , i n t t ) {
ned = 0 ; l l f l o w = K;
} f o r ( i n t i = t ; i != s ; i = t o [ prv [ i ] ^ 1 ] )
f l o w = min ( f l o w , cap [ prv [ i ] ] ) ;
void add ( i n t u , i n t v , l l f , l l c ) { f o r ( i n t i = t ; i != s ; i = t o [ prv [ i ] ^ 1 ] ) {
t o [ ned ] = v , cap [ ned ] = f ; cap [ prv [ i ] ] −= f l o w ;
c o s t [ ned ] = c , nxt [ ned ] = f i r s t [ u ] ; cap [ prv [ i ] ^ 1 ] += f l o w ;
f i r s t [ u ] = ned++; }
K −= f l o w ;
t o [ ned ] = u , cap [ ned ] = 0 ; l l f l o w C o s t = f l o w ∗ ( d i s t [ t ]− pot [ s ]+ pot [ t ] ) ;
c o s t [ ned ] = −c , nxt [ ned ] = f i r s t [ v ] ; f o r ( i n t i = 0 ; i < N; i ++)
f i r s t [ v ] = ned++; i f ( prv [ i ]!= −1) pot [ i ] += d i s t [ i ] ;
} return f l o w C o s t ;
}
bool d i j k s t r a ( i n t s , i n t t ) {
memset ( prv , −1, s i z e o f prv ) ; l l mincostmaxflow ( i n t s , i n t t ) {
f o r ( i n t i = 0 ; i < N; i ++) d i s t [ i ] = INF ; l l flowCost = 0;
s e t < p a i r <l l , int> > q ; memset ( pot , 0 , s i z e o f ( pot ) ) ;
q . i n s e r t ( make_pair ( 0LL , s ) ) ; while ( d i j k s t r a ( s , t ) ) {
d i s t [ s ] = prv [ s ] = 0 ; f l o w C o s t += augment ( s , t ) ;
int u , v ; }
while ( ! q . empty ( ) ) { return f l o w C o s t ;
u = q . b e g i n ( )−>s e c o n d ; }
CAPÍTULO 5. GRAFOS 39

5.21 Euler Tour: Algoritmo de Fleury


Computa o Euler Tour em O(V + E). Grafo indexado em 0. Retorna array vazia se não existe caminho. Procura automa-
ticamente o início caso haja algum nó ímpar. Usa a preferência passada pro caso em que todos os nós são ímpares ou 0 se
não há preferência.

#include <v e c t o r > c n t i n ++; s = u ;


#include <s t a c k > i f ( c n t i n == 2 ) return t o u r ;
#define MAXN 400009 }
using namespace s t d ; e l s e i f ( out [ u ] != i n [ u ] | | i n [ u]==0)
return t o u r ;
v e c t o r <int> a d j L i s t [MAXN] ; }
i n t N, M; s t a c k <int> d f s ;
d f s . push ( s ) ;
v e c t o r <int> e u l e r ( i n t s = 0 ) { while ( ! d f s . empty ( ) ) {
v e c t o r <int> work (N, 0 ) , i n (N, 0 ) , out (N, 0 ) , t o u r i n t u = d f s . top ( ) ;
; i f ( work [ u ] < ( i n t ) a d j L i s t [ u ] . s i z e ( ) ) {
f o r ( i n t u = 0 ; u < N; u++) { d f s . push ( a d j L i s t [ u ] [ work [ u ]++]) ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++) { }
int v = a d j L i s t [ u ] [ i ] ; else {
out [ u]++; i n [ v ]++; t o u r . push_back ( u ) ;
} d f s . pop ( ) ;
} }
int c n t i n = 0 , cntout = 0 ; }
f o r ( i n t u = 0 ; u < N; u++) { int n = tour . s i z e ( ) ;
i f ( i n [ u ] == out [ u ]+1) { f o r ( i n t i =0; 2∗ i <n ; i ++)
c n t o u t ++; swap ( t o u r [ i ] , t o u r [ n−i −1]) ;
i f ( c n t o u t == 2 ) return t o u r ; return t o u r ;
} }
e l s e i f ( out [ u ] == i n [ u ]+1) {

5.22 Dominator Tree


Computa a Dominator Tree em O((V + E)logV ). Precisa da lista de adjacência reversa. sdom[i] é o semi-dominator no
grafo mapeado por num, dom[i] é o immediate-dominator no grafo mapeado por num. idom[i] é o immediate-dominator
real. dtree é a dominator tree. A origem sempre é 1.

#include <v e c t o r > dsu [ u ] = b e s t [ u ] = sdom [ u ] = u ;


using namespace s t d ; }
#define MAXN 200009 cnt = 0 ;
dfs (1) ;
v e c t o r <int> a d j L i s t [MAXN] , r e v A d j L i s t [MAXN] ; f o r ( i n t j = c n t − 1 , u ; u = r e v [ j ] , j > 0 ; j −−)
v e c t o r <int> d t r e e [MAXN] ; {
i n t sdom [MAXN] , dom [MAXN] , idom [MAXN] , N, M; f o r ( i n t i = 0 ; i <( i n t ) r e v A d j L i s t [ u ] . s i z e ( ) ; i
i n t dsu [MAXN] , b e s t [MAXN] ; // a u x i l i a r e s ++) {
i n t par [MAXN] , num [MAXN] , r e v [MAXN] , c n t ; // d f s i n t y = num [ r e v A d j L i s t [ u ] [ i ] ] ;
i f ( y == −1) continue ;
int f i n d ( int x ) { find (y) ;
i f ( x == dsu [ x ] ) return x ; i f ( sdom [ b e s t [ y ] ] < sdom [ j ] ) sdom [ j ] = sdom
i n t y = f i n d ( dsu [ x ] ) ; [ best [ y ] ] ;
i f ( sdom [ b e s t [ x ] ] > sdom [ b e s t [ dsu [ x ] ] ] ) best [ x ] = }
b e s t [ dsu [ x ] ] ; d t r e e [ sdom [ j ] ] . push_back ( j ) ;
return dsu [ x ] = y ; i n t x = dsu [ j ] = par [ j ] ;
} f o r ( i n t i =0; i <( i n t ) d t r e e [ x ] . s i z e ( ) ; i ++) {
int z = d t r e e [ x ] [ i ] ;
void d f s ( i n t u ) { find (z ) ;
num [ u ] = c n t ; r e v [ c n t ++] = u ; i f ( sdom [ b e s t [ z ] ] < x ) dom [ z ] = b e s t [ z ] ;
f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++) { e l s e dom [ z ] = x ;
int v = a d j L i s t [ u ] [ i ] ; }
i f (num [ v ] >= 0 ) continue ; dtree [ x ] . clear () ;
dfs (v) ; }
par [ num [ v ] ] = num [ u ] ; idom [ 1 ] = −1;
} f o r ( i n t i = 1 ; i < c n t ; i ++) {
} i f ( sdom [ i ] != dom [ i ] ) dom [ i ] = dom [ dom [ i ] ] ;
idom [ r e v [ i ] ] = r e v [ dom [ i ] ] ;
void dominator ( ) { d t r e e [ r e v [ dom [ i ] ] ] . push_back ( r e v [ i ] ) ;
f o r ( i n t u = 1 ; u <= N; u++) { }
num [ u ] = −1; d t r e e [ u ] . c l e a r ( ) ; }
CAPÍTULO 5. GRAFOS 40

5.23 Grafos notáveis


Capítulo 6

Matemática

6.1 Aritmética Modular


MDC, MMC, euclides extendido, inverso modular a−1 (modm), divisão modular (a/b)(modm), exponenciação modular
ab (modm), solução inteira da equação de Diophantine ax + by = c. modM ul calcula (a ∗ b)%m sem overflow. Triângulo de
Pascal até 106 .

#include <c s t d i o > template<typename T>


#define MAXN 1000009 T modMul (T a , T b , T m) {
#define MOD 1000000007LL T x = 0 , y = a % m;
while ( b > 0 ) {
template <typename T> i f ( b % 2 == 1 ) x = ( x + y ) % m;
T gcd (T a , T b ) { y = ( y ∗ 2 ) % m;
return b == 0 ? a : gcd ( b , a % b ) ; b /= 2 ;
} }
return x % m;
template <typename T> }
T lcm (T a , T b ) {
return a ∗ ( b / gcd ( a , b ) ) ; template<typename T>
} T modExp (T a , T b , T m) {
i f ( b == 0 ) return 1 ;
template <typename T> T c = modExp ( a , b / 2 , m) ;
T extGcd (T a , T b , T& x , T& y ) { c = ( c ∗ c ) % m;
i f ( b == 0 ) { i f ( b % 2 != 0 ) c ∗= a ;
x = 1; y = 0; return c ;
return a ; }
}
else { template<typename T>
T g = extGcd ( b , a % b , y , x ) ; void d i o p h a n t i n e (T a , T b , T c , T& x , T& y ) {
y −= a / b ∗ x ; T d = extGcd ( a , b , x , y ) ;
return g ; x ∗= c / d ;
} y ∗= c / d ;
} }

template <typename T> l l f a t [MAXN] ;


T modInv (T a , T m) { void p r e p r o c e s s f a t ( ) {
T x, y; fat [ 0 ] = 1;
extGcd ( a , m, x , y ) ; f o r ( l l i =1; i <MAXN; i ++){
return ( x % m + m) % m; f a t [ i ] = ( i ∗ f a t [ i −1])%MOD;
} }
}
template <typename T>
T modDiv (T a , T b , T m) { template<typename T>
return ( ( a % m) ∗ modInv ( b , m) ) % m; T p a s c a l ( i n t n , i n t k , T m) {
} return modDiv ( f a t [ n ] , ( f a t [ k ] ∗ f a t [ n−k ] )%m, m) ;
}

41
CAPÍTULO 6. MATEMÁTICA 42

6.2 Números primos


Diversas operações com números primos. Crivo
√de Eristótenes, número de divisores, totiente de Euler e número de diferentes
fatores primos. isP rimeSieve funciona em O( n/logn) se os fatores estiverem em primes.

#include <b i t s e t > return true ;


#include <c s t d i o > }
#include <v e c t o r >
#include <c s t r i n g > v e c t o r <l l > p r i m e F a c t o r s ( l l N) {
using namespace s t d ; v e c t o r <int> f a c t o r s ;
#define MAXN 10000009 l l PF_idx = 0 , PF = p r i m e s [ PF_idx ] ;
while (PF ∗ PF <= N) {
typedef long long i n t l l ; while (N % PF == 0 ) {
l l s i e v e s i z e , numDiffPF [MAXN] ; N /= PF ;
b i t s e t <MAXN> bs ; f a c t o r s . push_back (PF) ;
v e c t o r <l l > p r i m e s ; }
PF = p r i m e s[++PF_idx ] ;
void s i e v e ( l l n ) { }
sievesize = n + 1; // s p e c i a l c a s e i f N i s a prime
bs . s e t ( ) ; i f (N != 1 ) f a c t o r s . push_back (N) ;
bs [ 0 ] = bs [ 1 ] = 0 ; return f a c t o r s ;
f o r ( l l i = 2 ; i <= s i e v e s i z e ; i ++) { }
i f ( bs [ i ] ) {
f o r ( l l j = i ∗ i ; j <= ( l l ) s i e v e s i z e ; j += l l numDiv ( l l N) {
i ) bs [ j ] = 0 ; l l PF_idx = 0 , PF = p r i m e s [ PF_idx ] , ans = 1 ; //
p r i m e s . push_back ( i ) ; s t a r t from ans = 1
} while (PF ∗ PF <= N) {
} l l power = 0 ; // c o u n t t h e power
} while (N % PF == 0 ) { N /= PF ; power++; }
ans ∗= ( power + 1 ) ; // a c c o r d i n g t o t h e
bool i s P r i m e S i e v e ( l l N) { formula
i f (N <= ( l l ) s i e v e s i z e ) return bs [N ] ; PF = p r i m e s[++PF_idx ] ;
f o r ( i n t i = 0 ; i < ( i n t ) p r i m e s . s i z e ( ) && p r i m e s [ }
i ] ∗ p r i m e s [ i ] <= N; i ++) // ( l a s t f a c t o r has pow = 1 , we add 1 t o i t )
i f (N % p r i m e s [ i ] == 0 ) return f a l s e ; i f (N != 1 ) ans ∗= 2 ;
return true ; return ans ;
} }

//O( s q r t ( n ) ) l l E u l e r P h i ( l l N) {
bool i s P r i m e ( l l N) { l l PF_idx = 0 , PF = p r i m e s [ PF_idx ] , ans = N;
i f (N < 0 ) return i s P r i m e (−N) ; while (PF ∗ PF <= N) {
f o r ( l l i =2; i ∗ i <= N; i ++){ i f (N % PF == 0 ) ans −= ans / PF ;
i f (N % i == 0 ) return f a l s e ; while (N % PF == 0 ) N /= PF ;
} PF = p r i m e s[++PF_idx ] ;
return true ; }
} i f (N != 1 ) ans −= ans / N;
return ans ;
//O( s q r t ( n ) ) c o r t e s i a do Fabinho }
bool i s P r i m e F a s t ( l l n ) {
i f ( n < 0 ) n = −n ; void numDiffPf ( ) {
i f ( n < 5 | | n % 2 == 0 | | n % 3 == 0 ) memset ( numDiffPF , 0 , s i z e o f numDiffPF ) ;
return ( n == 2 | | n == 3 ) ; f o r ( i n t i = 2 ; i < MAXN; i ++)
l l maxP = s q r t ( n ) + 2 ; i f ( numDiffPF [ i ] == 0 )
f o r ( l l p = 5 ; p < maxP ; p += 6 ) { f o r ( i n t j = i ; j < MAXN; j += i )
i f ( p < n && n % p == 0 ) return f a l s e ; numDiffPF [ j ]++;
i f ( p+2 < n && n % ( p+2) == 0 ) return f a l s e ; }
}

6.3 Fórmula de Legendre


Dados um inteiro n e um primo p, calcula o expoente da maior potência de p que divide n! em O(logn).

#include <c s t d i o > l l prod = p ;


#include <c s t r i n g > while ( prod <= n ) {
ans += n/ prod ;
typedef long long l l ; prod ∗= p ;
}
ll legendre ( l l n , l l p){ return ans ;
i n t ans = 0 ; }
CAPÍTULO 6. MATEMÁTICA 43

6.4 Números de Catalan


Computa os números de Catalan de 0 a n em O(nlogn). Dá pra fazer em O(n) para n pequeno.

• Cat(n) = número de arvores binárias completas de n + 1 folhas ou 2n + 1 elementos;


• Cat(n) = número de combinações válidas para n pares de parêntesis;
• Cat(n) = número de formas que o parentesiamento de n + 1 elementos pode ser feito;
• Cat(n) = número de triangulações de um polígono convexo de n + 2 lados; e
• Cat(n) = número de caminhos monotônicos discretos para ir de (0, 0) a (n, n).

typedef long long l l ; f o r ( i n t i =2; i <=n ; i ++){


l l c a t [MAXN] ; g = gcd ( 2 ∗ ( 2 ∗ i −1) , i +1) ;
c a t [ i ] = ( ( 2 ∗ ( 2 ∗ i −1) ) / g ) ∗ ( c a t [ i − 1 ] / ( ( i +1)/ g ) ) ;
void c a t a l a n ( i n t n ) { }
cat [ 0 ] = cat [ 1 ] = 1; }
ll g;

6.5 Algoritmo de Pollard-Rho


Retorna um fator de n, usar para n > 9 × 1013 .

#include <c s t d i o >


#include <a l g o r i t h m > template<typename T>
using namespace s t d ; T p o l l a r d (T n ) {
int i = 0 , k = 2 , d ;
template <typename T> T x = 3 , y = 3;
T gcd (T a , T b ) { while ( true ) {
... i ++;
} x = ( mulmod ( x , x , n ) + n − 1 ) % n ;
d = gcd ( abs ( y − x ) , n ) ;
template<typename T> i f ( d != 1 && d != n ) return d ;
T modMul (T a , T b , T m) { i f ( i == k ) y = x , k ∗= 2 ;
... }
} }

6.6 Baby-Step Giant-Step para Logaritmo Discreto



Resolve a equação ax = b(modm) em O( m logm). Retorna -1 se não há solução.

#include <c s t d i o > v a l s [ cur ] = i ;


#include <map> c u r = ( c u r ∗ an ) % m;
using namespace s t d ; }
f o r (T i =0 , c u r=b ; i <=n ; ++i ) {
template <typename T> i f ( v a l s . count ( c u r ) ) {
T baby (T a , T b , T m) { T ans = v a l s [ c u r ] ∗ n − i ;
a %= m; b %= m; i f ( ans < m)
T n = (T) s q r t (m + . 0 ) + 1 ; return ans ;
T an = 1 ; }
f o r (T i =0; i <n ; ++i ) c u r = ( c u r ∗ a ) % m;
an = ( an ∗ a ) % m; }
map<T, T> v a l s ; return −1;
f o r (T i =1 , c u r=an ; i <=n ; ++i ) { }
i f ( ! v a l s . count ( c u r ) )

6.7 Código de Gray


Converte para o cógido de gray, ida O(1) e volta O(logn).

int g ( int n ) { f o r ( ; g ; g>>=1)


return n ^ ( n >> 1 ) ; n ^= g ;
} return n ;
i n t rev_g ( i n t g ) { }
int n = 0 ;
CAPÍTULO 6. MATEMÁTICA 44

6.8 Teorema Chinês dos Restos


Resolve em O(nlogn) o sistema x = a[i](mod p[i]), 0 ≤ i < n, gcd(a[i], a[j]) = 1 para todo i 6= j.

template <typename T> T P = 1;


T extGcd (T a , T b , T& x , T& y ) { . . . } f o r ( i n t i =0; i <n ; i ++) P = (P ∗ p [ i ] ) % m;
T x = 0 , pp ;
template <typename T> f o r ( i n t i =0; i <n ; i ++){
T modInv (T a , T m) { . . . } pp = modDiv (P , p [ i ] , m) ;
x = (x + ((( a [ i ] ∗ pp ) % m) ∗ modInv ( pp , p [ i
template <typename T> ] ) ) ) % m;
T modDiv (T a , T b , T m) { . . . } }
return x ;
template<typename T> }
T c h i n e s e r t (T∗ a , T∗ p , i n t n , T m) {

6.9 Matrizes
#include <v e c t o r > matrix c ;
#include <cmath> c . r e s i z e (n) ;
#define EPS 1 e−5 f o r ( i n t i =0; i <n ; i ++){
using namespace s t d ; c [ i ] . a s s i g n (p , 0) ;
f o r ( i n t j =0; j <p ; j ++){
typedef long long l l ; f o r ( i n t k =0; k<m; k++){
typedef v e c t o r < v e c t o r < double > > m a t r i x ; c [ i ] [ j ] += a [ i ] [ k ] ∗ b [ k ] [ j ] ;
}
m a t r i x operator +( m a t r i x a , m a t r i x b ) { }
int n = ( int ) a . s i z e ( ) ; }
int m = ( int ) a [ 0 ] . s i z e ( ) ; return c ;
matrix c ; }
c . r e s i z e (n) ;
f o r ( i n t i =0; i <n ; i ++){ m a t r i x operator ∗ ( double k , m a t r i x a ) {
c [ i ] . r e s i z e (m) ; int n = ( int ) a . s i z e ( ) ;
f o r ( i n t j =0; j <m; j ++){ int m = ( int ) a [ 0 ] . s i z e ( ) ;
c [ i ][ j ] = a[ i ][ j ] + b[ i ][ j ]; f o r ( i n t i =0; i <n ; i ++){
} f o r ( i n t j =0; j <m; j ++){
} a [ i ] [ j ] ∗= k ;
return c ; }
} }
return a ;
m a t r i x operator ∗ ( m a t r i x a , m a t r i x b ) { }
int n = ( int ) a . s i z e ( ) ;
i f ( a [ 0 ] . s i z e ( ) != b . s i z e ( ) ) p r i n t f ( " f a i l \n" ) ; m a t r i x operator −( m a t r i x a , m a t r i x b ) {
int m = ( int ) b . s i z e ( ) ; return a + ( ( − 1 . 0 ) ∗ b ) ;
int p = ( int ) b [ 0 ] . s i z e ( ) ; }

6.10 Exponenciação de matrizes e Fibonacci


Calcula o n-ésimo termo de fibonacci em tempo O(logn). Calcula uma matriz elevado a n em O(m3 logn).

m a t r i x matrixExp ( m a t r i x a , i n t n ) { c [ 0 ] . a s s i g n (2 , 1) ;
i f ( n == 0 ) return i d ( a . s i z e ( ) ) ; c [ 1 ] . a s s i g n (2 , 1) ;
m a t r i x c = matrixExp ( a , n / 2 ) ; c [ 1 ] [ 1 ] = 0;
c = c∗c ; return c ;
i f ( n%2 != 0 ) c = c ∗ a ; }
return c ;
} double f i b o ( i n t n ) {
m a t r i x f = matrixExp ( f i b o ( ) , n ) ;
matrix f i b o ( ) { return f [ 0 ] [ 1 ] ;
matrix c ; c . r e s i z e ( 2 ) ; }
CAPÍTULO 6. MATEMÁTICA 45

6.11 Sistemas Lineares: Determinante e Eliminação de Gauss


Função para o determinante da matriz A pelo algoritmo de Chió em O(n3 ). gauss(A, B) retorna se o sistema Ax = B possui
solução e executa a eliminação de Gauss em A e B.

bool comlumnHasNonZero ( m a t r i x & a , i n t j ) { matrix c ; c . r e s i z e ( n ) ;


int n = ( int ) a . s i z e ( ) ; f o r ( i n t i =0; i <n ; i ++){
f o r ( i n t i = 0 ; i < n ; i ++){ c [ i ] . a s s i g n (n , 0) ;
i f ( f a b s ( a [ i ] [ j ] ) > EPS) return true ; c [ i ] [ i ] = 1;
} }
return f a l s e ; return c ;
} }

bool l i n e H a s N o n Z e r o ( m a t r i x & a , i n t i ) { double d e t ( m a t r i x a ) {


int m = ( int ) a [ 0 ] . s i z e ( ) ; int n = a . s i z e ( ) ;
f o r ( i n t j = 0 ; j < m; j ++){ i f ( n == 1 ) return a [ 0 ] [ 0 ] ;
i f ( f a b s ( a [ i ] [ j ] ) > EPS) return true ; double s i g = ( f i x ( a , 0 , 0 ) ? −1 : 1 ) ;
} m a t r i x b = i d ( n−1) ;
return f a l s e ; f o r ( i n t i =0; i <n−1; i ++){
} f o r ( i n t j =0; j <n−1; j ++){
b [ i ] [ j ] = a [ i + 1 ] [ j +1]∗ a [ 0 ] [ 0 ] − a [ i
bool hasNonZero ( m a t r i x & a ) { +1][0]∗ a [ 0 ] [ j +1];
int n = ( int ) a . s i z e ( ) ; }
f o r ( i n t i = 0 ; i < n ; i ++){ }
i f ( l i n e H a s N o n Z e r o ( a , i ) ) return true ; double d = d e t ( b ) /pow ( a [ 0 ] [ 0 ] , n−2) ;
} return s i g ∗d ;
return f a l s e ; }
}
void lineSumTo ( m a t r i x & a , i n t i , i n t j , double c ) {
void switchColumns ( m a t r i x & a , i n t i , i n t j ) { int m = ( int ) a [ 0 ] . s i z e ( ) ;
double tmp ; f o r ( i n t k =0; k<m; k++){
int n = ( int ) a . s i z e ( ) ; a [ j ] [ k ] += c ∗ a [ i ] [ k ] ;
f o r ( i n t k =0; k<n ; k++){ }
tmp = a [ k ] [ i ] ; }
a[k][ i ] = a[k][ j ];
a [ k ] [ j ] = tmp ; void columnSumTo ( m a t r i x & a , i n t i , i n t j , double c )
} {
} int n = ( int ) a . s i z e ( ) ;
f o r ( i n t k =0; k<n ; k++){
void s w i t c h L i n e s ( m a t r i x & a , i n t i , i n t j ) { a [ k ] [ j ] += c ∗ a [ k ] [ i ] ;
double tmp ; }
int m = ( int ) a [ i ] . s i z e ( ) ; }
f o r ( i n t k =0; k<m; k++){
tmp = a [ i ] [ k ] ; bool g a u s s ( m a t r i x & a , m a t r i x & b ) {
a[ i ][k] = a[ j ][k]; int n = ( int ) a . s i z e ( ) ;
a [ j ] [ k ] = tmp ; int m = ( int ) a [ 0 ] . s i z e ( ) ;
} double p ;
} f o r ( i n t i = 0 , l ; i < min ( n , m) ; i ++){
l = i;
bool f i x ( m a t r i x & a , i n t i , i n t j ) { while ( l < n && f a b s ( a [ l ] [ i ] )<EPS) l ++;
int n = ( int ) a . s i z e ( ) ; i f ( l == n ) return f a l s e ;
int m = ( int ) a [ 0 ] . s i z e ( ) ; switchLines (a , i , l ) ;
int l = i , c = j ; switchLines (b , i , l ) ;
bool s w i t c h e d = f a l s e ; f o r ( i n t j=i +1; j <n ; j ++){
while ( l < n && ! l i n e H a s N o n Z e r o ( a , l ) ) l ++; p = −a [ j ] [ i ] / a [ i ] [ i ] ;
i f ( l == n ) return f a l s e ; lineSumTo ( a , i , j , p ) ;
i f ( i != l ) { lineSumTo ( b , i , j , p ) ;
switched = ! switched ; }
switchLines (a , i , l ) ; }
} f o r ( i n t i=min ( n , m) −1; i >=0; i −−){
while ( c < m && f a b s ( a [ i ] [ c ] )<EPS) c++; f o r ( i n t j =0; j <i ; j ++){
i f ( j != c ) { p = −a [ j ] [ i ] / a [ i ] [ i ] ;
switched = ! switched ; lineSumTo ( a , i , j , p ) ;
switchColumns ( a , j , c ) ; lineSumTo ( b , i , j , p ) ;
} }
return s w i t c h e d ; }
} return true ;
}
matrix id ( int n ) {
CAPÍTULO 6. MATEMÁTICA 46

6.12 Multiplicação de matriz esparsa


Multiplica duas matrizes em O(n2 m), onde m é o mínimo do número médio de números não nulos em cada linha e coluna.

v e c t o r < v e c t o r <int> > adjA , adjB ; }


}
matrix sparsemult ( matrix a , matrix b ) { matrix c ;
int n = ( int ) a . s i z e ( ) ; c . r e s i z e (n) ;
i f ( a [ 0 ] . s i z e ( ) != b . s i z e ( ) ) p r i n t f ( " f a i l \n" ) ; f o r ( i n t i =0; i <n ; i ++){
int m = ( int ) b . s i z e ( ) ; c [ i ] . a s s i g n (p , 0) ;
int p = ( int ) b [ 0 ] . s i z e ( ) ; f o r ( i n t j =0; j <p ; j ++){
adjA . r e s i z e ( n ) ; f o r ( i n t u=0 , v=0 , k ; u<( i n t ) adjA [ i ] . s i z e ( )
f o r ( i n t i =0; i <n ; i ++) { && v<( i n t ) adjB [ j ] . s i z e ( ) ; ) {
adjA [ i ] . c l e a r ( ) ; i f ( adjA [ i ] [ u ] > adjB [ j ] [ v ] ) v++;
f o r ( i n t k =0; k<m; k++) { e l s e i f ( adjA [ i ] [ u ] < adjB [ j ] [ v ] ) u++;
i f ( f a b s ( a [ i ] [ k ] ) > EPS) else {
adjA [ i ] . push_back ( k ) ; k = adjA [ i ] [ u ] ;
} c [ i ] [ j ] += a [ i ] [ k ] ∗ b [ k ] [ j ] ;
} u++; v++;
adjB . r e s i z e ( p ) ; }
f o r ( i n t j =0; j <p ; j ++) { }
adjB [ j ] . c l e a r ( ) ; }
f o r ( i n t k =0; k<m; k++) { }
i f ( f a b s ( b [ k ] [ j ] ) > EPS) return c ;
adjB [ j ] . push_back ( k ) ; }

6.13 Método de Gauss-Seidel


Resolve o sistema linear iterativamente com complexidade O(n2 logP REC −1 ). É necessário que a diagonal principal seja
dominante.

m a t r i x g a u s s S e i d e l ( m a t r i x & a , m a t r i x & b , double i f ( i < j ) xp [ i ] [ 0 ] −= a [ i ] [ j ] ∗ xp [ j ] [ 0 ] ;


PREC) { i f ( i > j ) xp [ i ] [ 0 ] −= a [ i ] [ j ] ∗ x [ j ] [ 0 ] ;
int n = ( int ) a . s i z e ( ) ; }
m a t r i x x = b , xp = b ; xp [ i ] [ 0 ] /= a [ i ] [ i ] ;
double e r r o r ; e r r o r = max( e r r o r , f a b s ( xp [ i ] [ 0 ] − x [ i ] [ 0 ] ) ) ;
do { }
error = 0.0; x = xp ;
f o r ( i n t i =0; i <n ; i ++) { } while ( e r r o r > PREC) ;
xp [ i ] [ 0 ] = b [ i ] [ 0 ] ; return xp ;
f o r ( i n t j =0; j <n ; j ++) { }

6.14 Eliminação de Gauss com o XOR


gaussxor retorna o valor máximo de xor que é possível se obter fazendo xor entre os elementos da array. O(N logS).

#include <c s t d i o > swap ( a r r [ i ] , a r r [ t ] ) ;


#include <a l g o r i t h m > f o r ( i n t i =0; i <N; i ++){
using namespace s t d ; i f ( i != t && ( a r r [ i ] & s i g ) !=0)
#define MAXN 100009 a r r [ i ] ^= a r r [ t ] ;
}
typedef long long l l ; t ++;
}
l l g a u s s x o r ( l l ∗ a r r , i n t N) { cur = 0 ;
l l cur , s i g = ( 1LL << 6 2 ) ; f o r ( i n t i =0; i <N; i ++){
f o r ( i n t j =0 , t =0 , i ; s i g > 0 ; s i g >>= 1 ) { cur = cur^a r r [ i ] ;
i=t ; }
while ( i <N && ( a r r [ i ] & s i g ) ==0) i ++; return c u r ;
i f ( i >= N) continue ; }
CAPÍTULO 6. MATEMÁTICA 47

6.15 Fast Fourier Transform (FFT)


Usar em caso de double. Em caso de inteiro converter com f a[i].real() + 0.5. Não dá overflow.

#include <v e c t o r > b a s e u = a [ i+j ] , v = a [ i+j+l e n / 2 ] ∗ w ;


#include <c s t d i o > a [ i+j ] = u + v ;
#include <complex> a [ i+j+l e n / 2 ] = u − v ;
using namespace s t d ; w ∗= wlen ;
}
typedef complex<double> b a s e ; }
}
void f f t ( v e c t o r <base> & a , bool i n v e r t ) { if ( invert )
int n = ( int ) a . s i z e ( ) ; f o r ( i n t i =0; i <n ; ++i )
f o r ( i n t i =1 , j =0; i <n ; ++i ) { a [ i ] /= n ;
i n t b i t = n >> 1 ; }
f o r ( ; j>=b i t ; b i t >>=1)
j −= b i t ; void c o n v o l u t i o n ( v e c t o r <base> a , v e c t o r <base> b ,
j += b i t ; v e c t o r <base> & r e s ) {
if ( i < j ) int n = 1 ;
swap ( a [ i ] , a [ j ] ) ; while ( n < max ( a . s i z e ( ) , b . s i z e ( ) ) ) n <<= 1 ;
} n <<= 1 ;
a . r e s i z e (n) , b . r e s i z e (n) ;
f o r ( i n t l e n =2; l e n<=n ; l e n <<=1) { f f t (a , false ) ; f f t (b , false ) ;
double ang = 2∗M_PI/ l e n ∗ ( i n v e r t ? −1 : 1 ) ; res . r e s i z e (n) ;
b a s e wlen ( c o s ( ang ) , s i n ( ang ) ) ; f o r ( i n t i =0; i <n ; ++i ) r e s [ i ] = a [ i ] ∗ b [ i ] ;
f o r ( i n t i =0; i <n ; i+=l e n ) { f f t ( r e s , true ) ;
base w (1) ; }
f o r ( i n t j =0; j <l e n / 2 ; ++j ) {

6.16 Number Theoretic Transform (NTT)


Usar long long. Cuidado com overflow. Não recomendado para valores no vetor maiores que 106 .

#include <v e c t o r > f o r ( l l i =0; i <n ; i+=l e n ) {


#include <c s t d i o > f o r ( l l j =0 , w=1; j <l e n / 2 ; ++j ) {
#define MAXN 100009 l l u = a [ i+j ] , v = a [ i+j+l e n / 2 ] ∗ w %
using namespace s t d ; mod ;
a [ i+j ] = ( u+v < mod ? u+v : u+v−mod) ;
typedef long long l l ; a [ i+j+l e n / 2 ] = ( u−v >= 0 ? u−v : u−v+mod
);
template <typename T> w = w ∗ wlen % mod ;
T extGcd (T a , T b , T& x , T& y ) { . . . } }
}
template <typename T> }
T modInv (T a , T m) { . . . } if ( invert ) {
l l n r e v = modInv ( n , mod) ;
const ll mod = 7 3 4 0 0 3 3 ; f o r ( l l i =0; i <n ; ++i )
const ll root = 5; a [ i ] = a [ i ] ∗ n r e v % mod ;
const ll root_1 = 4 4 0 4 0 2 0 ; }
const ll root_pw = 1<<20; }

void n t t ( v e c t o r <l l > & a , bool i n v e r t ) { void c o n v o l u t i o n ( v e c t o r <l l > a , v e c t o r <l l > b , v e c t o r
l l n = ( l l ) a . size () ; <l l > & r e s ) {
f o r ( l l i =1 , j =0; i <n ; ++i ) { l l n = 1;
l l b i t = n >> 1 ; while ( n < max ( a . s i z e ( ) , b . s i z e ( ) ) ) n <<= 1 ;
f o r ( ; j>=b i t ; b i t >>=1) j −= b i t ; n <<= 1 ;
j += b i t ; a . r e s i z e (n) , b . r e s i z e (n) ;
i f ( i < j ) swap ( a [ i ] , a [ j ] ) ; ntt (a , false ) ; ntt (b , false ) ;
} res . r e s i z e (n) ;
f o r ( l l l e n =2 , wlen ; l e n<=n ; l e n <<=1) { f o r ( i n t i =0; i <n ; ++i ) r e s [ i ] = ( a [ i ] ∗ b [ i ] )%mod ;
wlen = i n v e r t ? root_1 : r o o t ; n t t ( r e s , true ) ;
f o r ( l l i=l e n ; i <root_pw ; i <<=1) }
wlen = ( wlen ∗ wlen % mod) ;
CAPÍTULO 6. MATEMÁTICA 48

6.17 Convolução circular


Pn−1
Utiliza FFT/NTT para computar em O(nlogn): res[i] = j=0 a[j] ∗ b[(i − j + n)%n]

template <typename T> convolution (a , b , res ) ;


void c i r c u l a r c o n v o l u t i o n ( v e c t o r <T> a , v e c t o r <T> b , r e s = v e c t o r <T>( r e s . b e g i n ( )+n , r e s . b e g i n ( ) +(2∗n ) )
v e c t o r <T> & r e s ) { ;
int n = a . s i z e ( ) ; }
b . i n s e r t ( b . end ( ) , b . b e g i n ( ) , b . end ( ) ) ;

6.18 Triplas Pitagóricas


Todas as triplas pitagóricas (a, b, c), a2 + b2 = c2 podem ser geradas a partir das equações:

a = k(m2 − n2 ), b = 2kmn, c = k(m2 + n2 ) (6.1)

Triplas primiticas são geradas por k = 1.



• tripleF romHypot, O(f c), onde f é o número de divisores de c (f ≤ 450 para c ≤ 107 ), retorna os possíveis pares
(a, b) dado c.

• primitiveT ripleF romHypot, O( c), retorna os possíveis pares primitivos (a, b) dado c.
• tripleF romSide, O(a), retorna os possíveis de pares (b, c) dado a.

#include <c s t d i o > s = c /k ;


#include <cmath> a d d S i d e s ( ans , s , k ) ;
#include <s e t > a d d S i d e s ( ans , k , s ) ;
#include <i o s t r e a m > }
using namespace s t d ; return ans ;
}
typedef p a i r <int , int> i i ; s e t <i i > p r i m i t i v e T r i p l e F r o m H y p o t ( i n t c ) {
s e t <i i > ans ;
i n l i n e void a d d S i d e s ( s e t <i i > & ans , i n t k , i n t s ) { a d d S i d e s ( ans , 1 , c ) ;
f o r ( i n t n=1 , m, ms , a , b ; n∗n<=s / 2 ; n++){ return ans ;
ms = s − n∗n ; }
m = f l o o r ( s q r t ( ms ) ) ; s e t <i i > t r i p l e F r o m S i d e ( i n t a ) {
i f (m∗m == ms && m!=n ) { s e t <i i > ans ;
a = m∗m − n∗n ; f o r ( i n t n = 1 , m, b , c ; n < a ; n++){
b = 2∗m∗n ; i f ( a%n != 0 ) continue ;
ans . i n s e r t ( i i ( k∗a , k∗b ) ) ; m = a ∗ a /n ;
ans . i n s e r t ( i i ( k∗b , k∗ a ) ) ; i f (m%2 != n%2) continue ;
} b = (m−n ) / 2 ;
} c = (m+n ) / 2 ;
} ans . i n s e r t ( i i ( b , c ) ) ;
s e t <i i > t r i p l e F r o m H y p o t ( i n t c ) { }
s e t <i i > ans ; return ans ;
f o r ( i n t k = 1 , s ; k∗k <= c ; k++){ }
i f ( c%k != 0 ) continue ;

6.19 Algoritmo de Floyd


Achar ciclos em sequências an = f (an−1 ) em O(n).

#include <i o s t r e a m > // 2nd p a r t : f i n d i n g s t a r t , h a r e and t o r t o i s e


using namespace s t d ; move a t t h e same s p e e d
i n t s t a r t = 0 ; h a r e = x0 ;
typedef p a i r <int , int> i i ; while ( t o r t o i s e != h a r e ) { t o r t o i s e = f ( t o r t o i s e )
; h a r e = f ( h a r e ) ; s t a r t ++;}
i i f l o y d C y c l e F i n d i n g ( i n t x0 ) { // 3 rd p a r t : f i n d i n g p e r i o d , h a r e moves , t o r t o i s e
// 1 s t p a r t : f i n d i n g k ∗ s t a r t , h a r e s s p e e d i s 2 x stays
tortoises int period = 1 ; hare = f ( t o r t o i s e ) ;
i n t t o r t o i s e = f ( x0 ) , h a r e = f ( f ( x0 ) ) ; // f ( x0 ) while ( t o r t o i s e != h a r e ) { h a r e = f ( h a r e ) ; p e r i o d
i s t h e node n e x t t o x0 ++; }
while ( t o r t o i s e != h a r e ) { t o r t o i s e = f ( t o r t o i s e ) return i i ( s t a r t , p e r i o d ) ;
; hare = f ( f ( hare ) ) ; } }
CAPÍTULO 6. MATEMÁTICA 49

6.20 Bignum em C++


print imprime o número. f ix remove os zeros à frente. str2bignum converte de string para para bignum. int2bignum gera
um bignum a partir de um inteiro menor que a base. bignum2int só funciona se não der overflow. A divisão por inteiros só
funciona para inteiros menores que a base. Soma, subtração, shift left e shift right em O(n), multiplicação, divisão e resto
em O(n2 ). A subtração só funciona para a >= b.

#include <v e c t o r > return a ;


#include <a l g o r i t h m > }
#include <c s t d i o > bignum operator −(bignum a , bignum & b ) {
#include <c s t d l i b > int carry = 0 ;
#include <c s t r i n g > f o r ( s i z e _ t i =0; i <b . s i z e ( ) | | c a r r y ; ++i ) {
using namespace s t d ; a [ i ] −= c a r r y + ( i < b . s i z e ( ) ? b [ i ] : 0 ) ;
carry = a [ i ] < 0;
typedef v e c t o r <int> bignum ; i f ( c a r r y ) a [ i ] += b a s e ;
const i n t b a s e = 1 0 0 0 ∗ 1 0 0 0 ∗ 1 0 0 0 ; }
fix (a) ;
void p r i n t ( bignum & a ) { return a ;
p r i n t f ( "%d" , a . empty ( ) ? 0 : a . back ( ) ) ; }
f o r ( i n t i =( i n t ) a . s i z e ( ) −2; i >=0; −−i ) bignum operator ∗ ( i n t b , bignum a ) {
p r i n t f ( "%01d" , a [ i ] ) ; int carry = 0 ;
} f o r ( s i z e _ t i =0; i <a . s i z e ( ) | | c a r r y ; ++i ) {
void f i x ( bignum & a ) { i f ( i == a . s i z e ( ) )
while ( a . s i z e ( ) > 1 && a . back ( ) == 0 ) a . push_back ( 0 ) ;
a . pop_back ( ) ; long long c u r = c a r r y + a [ i ] ∗ 1 l l ∗ b ;
} a [ i ] = int ( cur % base ) ;
bool operator < ( bignum a , bignum b ) { carry = int ( cur / base ) ;
f i x (a) ; f i x (b) ; }
i f ( a . s i z e ( ) != b . s i z e ( ) ) return a . s i z e ( ) < b . fix (a) ;
size () ; return a ;
f o r ( i n t i =( i n t ) a . s i z e ( ) −1; i >=0; i −−){ }
i f ( a [ i ] != b [ i ] ) return a [ i ] < b [ i ] ; bignum operator ∗ ( const bignum & a , const bignum & b
} ){
return f a l s e ; bignum c ( a . s i z e ( )+b . s i z e ( ) ) ;
} f o r ( s i z e _ t i =0; i <a . s i z e ( ) ; ++i )
bignum s t r 2 b i g n u m ( char∗ s ) { f o r ( i n t j =0 , c a r r y =0; j <( i n t ) b . s i z e ( ) | |
bignum a ; c a r r y ; ++j ) {
f o r ( i n t i =( i n t ) s t r l e n ( s ) ; i >0; i −=9) { long long c u r = c [ i+j ] + a [ i ] ∗ 1 l l ∗ ( j <
s [ i ] = 0; ( int ) b . s i z e ( ) ? b [ j ] : 0) + carry ;
a . push_back ( a t o i ( i >=9 ? s+i −9 : s ) ) ; c [ i+j ] = i n t ( c u r % b a s e ) ;
} carry = int ( cur / base ) ;
fix (a) ; }
return a ; fix (c) ;
} return c ;
bignum int2bignum ( i n t n ) { }
bignum a ; bignum operator / ( bignum a , i n t b ) {
i f ( n == 0 ) a . push_back ( 0 ) ; int carry = 0 ;
while ( n > 0 ) { f o r ( i n t i =( i n t ) a . s i z e ( ) −1; i >=0; −−i ) {
a . push_back ( n%b a s e ) ; long long c u r = a [ i ] + c a r r y ∗ 1 l l ∗ b a s e ;
n /= b a s e ; a [ i ] = int ( cur / b ) ;
} carry = int ( cur % b ) ;
return a ; }
} fix (a) ;
i n t bignum2int ( bignum & a ) { return a ;
i n t ans = 0 , p=1; }
f o r ( i n t i =0; i <( i n t ) a . s i z e ( ) ; i ++){ bignum operator <<(bignum a , i n t b ) {
ans += a [ i ] ∗ p ; a . r e s i z e ( ( int ) a . s i z e ( ) + b) ;
p ∗= b a s e ; f o r ( i n t i =( i n t ) a . s i z e ( ) −1; i >=0; i −−){
} i f ( i >=b ) a [ i ] = a [ i −b ] ;
return ans ; else a [ i ] = 0;
} }
bignum operator +(bignum a , bignum b ) { return a ;
int carry = 0 ; }
f o r ( s i z e _ t i =0; i <max( a . s i z e ( ) , b . s i z e ( ) ) | | bignum operator >>(bignum a , i n t b ) {
c a r r y ; ++i ) { f o r ( i n t i =0; i+b<( i n t ) a . s i z e ( ) ; i ++){
i f ( i == a . s i z e ( ) ) a [ i ] = a [ i+b ] ;
a . push_back ( 0 ) ; }
a [ i ] += c a r r y + ( i < b . s i z e ( ) ? b [ i ] : 0 ) ; while ( b−−>0) a . pop_back ( ) ;
c a r r y = a [ i ] >= b a s e ; return a ;
i f ( c a r r y ) a [ i ] −= b a s e ; }
} bignum operator / ( bignum a , bignum b ) {
fix (a) ; bignum c , d ;
CAPÍTULO 6. MATEMÁTICA 50

c = int2bignum ( 1 ) ; a = ( a−b ) ; d = ( d+c ) ;


d = int2bignum ( 0 ) ; }
while ( b < a ) { return d ;
c = ( c <<1) ; b = ( b<<1) ; }
} bignum operator %(bignum a , bignum b ) {
while ( true ) { bignum c = a /b ;
while ( a < b && int2bignum ( 0 ) < c ) { c = b∗ c ;
c = ( c >>1) ; b = ( b>>1) ; return a−c ;
} }
i f ( ! ( int2bignum ( 0 ) < c ) ) break ;

6.21 BigInteger em Java


Sintaxe da classe BigInteger do Java.

import j a v a . u t i l . S c a n n e r ; BigInteger V = sc . nextBigInteger () ;


import j a v a . math . B i g I n t e g e r ; sum = sum . add (V) ;
}
c l a s s Main { /∗ UVa 10925 − Krakovia ∗/ System . out . p r i n t l n ( " B i l l ␣#" +
public s t a t i c void main ( S t r i n g [ ] a r g s ) { ( caseNo++) + " ␣ c o s t s ␣ " + sum +
S c a n n e r s c = new S c a n n e r ( System . i n ) ; " : ␣ each ␣ f r i e n d ␣ s h o u l d ␣ pay ␣ " +
i n t caseNo = 1 ; sum . d i v i d e ( B i g I n t e g e r . v a l u e O f (F) ) ) ;
while ( true ) { System . out . p r i n t l n ( ) ;
int N = sc . nextInt ( ) , F = sc . nextInt ( ) ; }
i f (N == 0 && F == 0 ) break ; }
B i g I n t e g e r sum = B i g I n t e g e r .ZERO; }
f o r ( i n t i = 0 ; i < N; i ++) {

6.22 Jogo de Nim


Determina se o primerio jogador tem a estratégia em um jogo de Nim. Para o jogo de Nim simples (a partir de uma pilha
de tamanho u, pode-se deixar a pilha de qualquer tamanho v ≥ 0), a soma de Nim vale S1 ⊕ S2 ⊕ ... ⊕ Sn . Para jogos mais
complexos, deve-se montar o grafo de posições alcançáveis para cada pilha. adjP os(i, u) deve retornar as posições alcançáveis
a partir da posição u na pilha i. Para problemas que envolvem a separação em vários subproblemas, montar uma PD para
calcular o mex de cada estado.

#include <v e c t o r > i f (G[ j ] == g [ u ] ) g [ u]++;


#include <a l g o r i t h m > }
using namespace s t d ; }
#define MAXN 109 ans ^= g [ S [ i ] ] ;
#define MAXM 1009 }
return ans != 0 ;
i n t N, S [MAXN] ; }

v e c t o r <int> a d j P o s ( i n t i , i n t u ) { //Mex dynamic programming


...
} void s t e v e h a l i m ( ) {
f o r ( i n t n=1; n<MAXN; n++) {
bool nim ( ) { i f ( n <= 2 ) { mex [ n ] = 0 ; continue ; }
i n t ans = 0 , g [MAXM] ; s e t <int> j o g ;
v e c t o r <int> F , G; f o r ( i n t i =3; i <=n−2; i ++) {
f o r ( i n t i =0; i <N; i ++){ j o g . i n s e r t ( mex [ i −1]^mex [ n−i ] ) ;
g [ 0 ] = 0; }
f o r ( i n t u=1; u<=S [ i ] ; u++){ int cnt = 0 ;
F = adjPos ( i , u ) ; while ( j o g . count ( c n t ) ) c n t ++;
G. c l e a r ( ) ; mex [ n ] = c n t ;
f o r ( i n t j =0; j <( i n t )F . s i z e ( ) ; j ++){ }
G. push_back ( g [ F [ j ] ] ) ; // f o r ( i n t n=1; n<MAXN; n++)
} // p r i n t f ("%d , " , mex [ n ] ) ;
s o r t (G. b e g i n ( ) , G. end ( ) ) ; }
g [ u ] = 0;
f o r ( i n t j =0; j <( i n t )G. s i z e ( ) && G[ j ] <= g [ u
] ; j ++){
Capítulo 7

Processamento de Strings

7.1 Knuth-Morris-Pratt (KMP)


String matching em O(n + m). Inicializar a classe com a string a ser procurada e usar match para receber o vector com as
posições de matches.

#include <c s t d i o > i ++; j ++;


#include <s t r i n g > b[ i ] = j ;
#include <v e c t o r > }
#include <c s t r i n g > }
using namespace s t d ; v e c t o r <int> match ( const char∗ T) {
#define MAXN 100009 n = s t r l e n (T) ;
v e c t o r <int> ans ;
c l a s s KMP{ f o r ( i n t i =0 , j =0; i < n ; ) {
private : while ( j >= 0 && T [ i ] != P [ j ] ) j = b [ j ] ;
char P [MAXN] ; i ++; j ++;
i n t m, n , b [MAXN] ; i f ( j == m) {
public : ans . push_back ( i − j ) ;
KMP( const char∗ _P) { j = b[ j ];
s t r c p y (P , _P) ; }
b [ 0 ] = −1; }
m = s t r l e n (P) ; return ans ;
f o r ( i n t i = 0 , j = −1; i < m; ) { }
while ( j >= 0 && P [ i ] != P [ j ] ) j = b [ j ] ; };

7.2 Rabin-Karp
String matching em O(n+m). Retorna o vector com as posições de matches. AVISO: Usa strncmp, não strcmp. CUIDADO:
Roda em O(nm) para casos do tipo AAAAAAAAAAAAAA − AAAA ou ABABABABABABABAB − ABABABA.

#include <c s t d i o > p = ( d∗p + P [ i ] )%MOD;


#include <c s t r i n g > t = ( d∗ t + T [ i ] )%MOD;
#include <v e c t o r > }
using namespace s t d ; f o r ( i n t i = 0 ; i <= n−m; i ++){
#define d 256 //Tamanho do a l f a b e t o i f ( p == t && strncmp (T+i , P , m) == 0 ) {
#define MOD 40031 ans . push_back ( i ) ;
}
v e c t o r <int> r a b i n k a r p ( const char∗ P , const char∗ T) { i f ( i+m < n ) {
v e c t o r <int> ans ; t = ( d ∗ ( t − T [ i ] ∗ h ) + T [ i+m] )%MOD;
i n t n = s t r l e n (T) ; i f ( t < 0 ) t += MOD;
i n t m = s t r l e n (P) ; }
int p = 0 , t = 0 , h = 1 ; }
f o r ( i n t i = 0 ; i < m−1; i ++) h = ( h∗d )%MOD; return ans ;
f o r ( i n t i = 0 ; i < m; i ++){ }

51
CAPÍTULO 7. PROCESSAMENTO DE STRINGS 52

7.3 Repetend: menor período de uma string


Menor período da string em O(n).

#include <c s t d i o > while ( j >= 0 && s [ j ] != s [ i − 1 ] )


#include <c s t r i n g > j = nxt [ j ] ;
#define MAXN 100009 nxt [ i ] = j + 1 ;
}
i n t r e p e t e n d ( char∗ s ) { i n t a = n − nxt [ n ] ;
int n = s t r l e n ( s ) ; i f ( n % a == 0 )
i n t nxt [ n + 1 ] ; return a ;
nxt [ 0 ] = −1; return n ;
f o r ( i n t i = 1 ; i <= n ; i ++) { }
i n t j = nxt [ i − 1 ] ;

7.4 Suffix Array


Algoritmo O(nlogn) para computar a Suffix Array SA.

#define MAXN 100009 }


#include <a l g o r i t h m > f o r ( i = 0 ; i < n ; i ++) tempSA [ c [ SA [ i ]+k < n ?
#include <c s t d i o > RA[ SA [ i ]+k ] : 0]++] = SA [ i ] ;
#include <c s t r i n g > f o r ( i = 0 ; i < n ; i ++) SA [ i ] = tempSA [ i ] ;
using namespace s t d ; }

char s t r [MAXN] ; void c o n s t r u c t S A ( ) { //O( n l o g n )


i n t n ; // t h e l e n g t h o f i n p u t s t r i n g int i , k , r ;
i n t RA[MAXN] , tempRA [MAXN] ; f o r ( i = 0 ; i < n ; i ++) RA[ i ] = s t r [ i ] ;
i n t SA [MAXN] , tempSA [MAXN] ; //SA : s u f f i x a r r a y f o r ( i = 0 ; i < n ; i ++) SA [ i ] = i ;
i n t c [MAXN] ; f o r ( k = 1 ; k < n ; k <<= 1 ) {
countingSort (k) ;
void c o u n t i n g S o r t ( i n t k ) { // O( n ) countingSort (0) ;
i n t i , sum , maxi = max ( 3 0 0 , n ) ; tempRA [ SA [ 0 ] ] = r = 0 ;
memset ( c , 0 , s i z e o f c ) ; f o r ( i = 1 ; i < n ; i ++) tempRA [ SA [ i ] ] =
f o r ( i = 0 ; i < n ; i ++) c [ i + k < n ? RA[ i + k ] (RA[ SA [ i ] ] == RA[ SA [ i − 1 ] ] && RA[ SA [ i ]+k ] ==
: 0]++; RA[ SA [ i −1]+k ] ) ? r : ++r ;
f o r ( i = sum = 0 ; i < maxi ; i ++) { f o r ( i = 0 ; i < n ; i ++) RA[ i ] = tempRA [ i ] ;
int t = c [ i ] ; i f (RA[ SA [ n − 1 ] ] == n−1) break ;
c [ i ] = sum ; }
sum += t ; }

7.5 Suffix Array: string matching


String matching em O(mlogn). Requer construção da SA.

i i s t r i n g M a t c h i n g ( char∗ P) { mid = ( l o + hi ) / 2;
i n t l o = 0 , h i = n−1 , mid = l o ; int r e s = strncmp ( s t r + SA [ mid ] , P , m) ;
while ( l o < h i ) { // f i n d l o w e r bound if ( res > 0 ) h i = mid ;
mid = ( l o + h i ) / 2 ; else lo = mid + 1 ;
i n t r e s = strncmp ( s t r + SA [ mid ] , P , m) ; }
i f ( r e s >= 0 ) h i = mid ; i f ( strncmp ( s t r + SA [ h i ] , P , m) != 0 ) hi −−; //
e l s e l o = mid + 1 ; s p e c i a l case
} ans . s e c o n d = h i ;
i f ( strncmp ( s t r + SA [ l o ] , P , m) != 0 ) return i i return ans ;
( −1 , −1) ; } // r e t u r n l o w e r / upperbound as f i r s t / s ec o nd item o f
i i ans ; ans . f i r s t = l o ; the pair , r e s p e c t i v e l y
l o = 0 ; h i = n − 1 ; mid = l o ;
while ( l o < h i ) { // i f l o w e r bound i s found ,
f i n d upper bound
CAPÍTULO 7. PROCESSAMENTO DE STRINGS 53

7.6 Suffix Array: Longest Common Prefix


LCP [i] guarda o tamanho do maior prefixo comum entre SA[i] e SA[i − 1].

i n t Phi [MAXN] ; i f ( Phi [ i ] == −1) {


i n t LCP [MAXN] , PLCP [MAXN] ; PLCP [ i ] = 0 ; continue ;
}
// L o n g e s t Common P r e f i x while ( s t r [ i + L ] == s t r [ Phi [ i ] + L ] ) L++;
SA [ i ] and SA [ i −1] PLCP [ i ] = L ;
void computeLCP ( ) { //O( n ) L = max( L−1 , 0 ) ;
int i , L ; }
Phi [ SA [ 0 ] ] = −1; f o r ( i = 0 ; i < n ; i ++) LCP [ i ] = PLCP [ SA [ i ] ] ;
f o r ( i = 1 ; i < n ; i ++) Phi [ SA [ i ] ] = SA [ i − 1 ] ; }
f o r ( i = L = 0 ; i < n ; i ++) {

7.7 Suffix Array: Longest Repeated Substring


É o valor do maior LCP.

i n t LRS ( ) { //O( n ) return l r s ;


int l r s = 0 ; }
f o r ( i n t i =0; i <n ; i ++) i f (LCP [ i ] > LCP [ l r s ] ) lrs
= i;

7.8 Suffix Array: Longest Common Substring


Retorna o tamanho da maior substring comum a str1 e str2.

i n t LCS( char∗ s t r 1 , char∗ s t r 2 ) { i f (LCP [ i ] > LCP [ ans ] &&


i n t n1 = s t r l e n ( s t r 1 ) ; ( ( SA [ i ]<n1 && SA [ i −1]>n1 ) | | (SA [ i ]>n1 &&
strcpy ( str , s t r 1 ) ; s t r c a t ( str , "$" ) ; SA [ i −1]<n1 ) ) ) {
s t r c a t ( s t r , s t r 2 ) ; s t r c a t ( s t r , "#" ) ; ans = i ;
n = strlen ( str ) ; }
c o n s t r u c t S A ( ) ; computeLCP ( ) ; }
i n t ans = 0 ; return LCP [ ans ] ;
f o r ( i n t i =1; i <n ; i ++){ }

7.9 Longest Palindromic Substring: Algoritmo de Manacher


Usado para achar a maior substring palíndromo. A função manacher calcula a array L. L[i] é o máximo valor possível tal
que str[i + j] = str[i − j], 0 ≤ j ≤ L[i]. Pra calcular os palíndromos pares, basta adicionar ‘|’ entre todos os caracateres e
calcular o maior valor de L da string.

#include <c s t d i o > }


#include <c s t r i n g >
#include <a l g o r i t h m > i n t LPS( char∗ t e x t ) {
#define MAXN 3009 i n t n=2∗ s t r l e n ( t e x t ) +1;
using namespace s t d ; char temp [ n + 1 ] ;
f o r ( i n t i =0 , k =0; t e x t [ i ] ; i ++) {
void manacher ( char∗ s t r , i n t ∗ L) { temp [ k++]= ’ | ’ ; temp [ k++]=t e x t [ i ] ;
int n = s t r l e n ( s t r ) , c = 0 , r = 0 ; }
f o r ( i n t i = 0 ; i < n ; i ++) { temp [ n−1]= ’ | ’ ; temp [ n]= ’ \0 ’ ;
i f ( i < r && 2∗ c >= i ) L [ i ] = min (L [ 2 ∗ c−i ] , r i n t L [ n ] , ans =1;
−i ) ; manacher ( temp , L) ;
else L [ i ] = 0; f o r ( i n t i =0; i <n ; i ++)
while ( i −L [ i ] −1 >= 0 && i+L [ i ]+1 < n && ans = max( ans , L [ i ] ) ;
s t r [ i −L [ i ] − 1 ] == s t r [ i+L [ i ] + 1 ] ) L [ i ]++; return ans ;
i f ( i+L [ i ]> r ) { c=i ; r=i+L [ i ] ; } }
}
CAPÍTULO 7. PROCESSAMENTO DE STRINGS 54

7.10 Aho Corasick


Resolve o problema de achar ocorrências de um dicionário em um texto em O(n), onde n é o comprimento do texto. Pré-
processamento: O(m), onde m é a soma do número de caracteres de todas as palavras do dicionário. Cuidado: o número
de matches pode ser W orst case O(n2 )! Guardar apenas o número de matches, se for o que o problema pedir. Pode ser
usada pra achar uma submatriz dentro de uma matriz (usar pra achar a ocorrência de cada linha dentro da outra, depois
usar KMP nas colunas com a array de ids).

#include <c s t d i o > x = q . f r o n t ( ) ; q . pop ( ) ;


#include <c s t r i n g > f o r ( i n t i = 0 ; i < ( i n t ) x−>a d j . s i z e ( ) ; i
#include <map> ++) {
#include <queue> y = x−>n e x t [ x−>a d j [ i ] ] ;
#include <v e c t o r > y−> f a i l = s u f f i x ( x−>f a i l , x−>a d j [ i ] ) ;
using namespace s t d ; y−>p a t s . i n s e r t ( y−>p a t s . end ( ) ,
#define ALFA 256 y−>f a i l −>p a t s . b e g i n ( ) , y−>f a i l −>p a t s .
#define MOD 1000000009 end ( ) ) ;
#define MAXK 70 q . push ( y ) ;
#define MAXN 100009 }
}
typedef p a i r <int , int> i i ; }
void i n s e r t ( const char∗ s , i n t i d ) {
struct node { int l e n = s t r l e n ( s ) ;
node ∗ f a i l , ∗ n e x t [ALFA ] ; s i z e s [ id ] = len ;
v e c t o r <char> a d j ; node ∗x = t r i e , ∗y ;
v e c t o r <int> p a t s ; f o r ( i n t i = 0 ; i < l e n ; i ++) {
int nid ; y = x−>n e x t [ s [ i ] ] ;
node ( i n t _nid ) { i f ( y == NULL | | y == t r i e ) {
f a i l = NULL; x−>n e x t [ s [ i ] ] = new node ( s i z e ++) ;
n i d = _nid ; x−>a d j . push_back ( s [ i ] ) ;
memset(&next , 0 , s i z e o f n e x t ) ; }
} x = x−>n e x t [ s [ i ] ] ;
}; }
x−>p a t s . push_back ( i d ) ;
c l a s s AhoCorasick }
{ v e c t o r <i i > match ( const char ∗ s ) {
private : node ∗ x = t r i e ;
node ∗ t r i e ; int l e n = s t r l e n ( s ) , id ;
map<int , int> s i z e s ; v e c t o r <i i > ans ;
int s i z e ; f o r ( i n t i = 0 ; i < l e n ; i ++) {
node ∗ s u f f i x ( node ∗x , char c ) { x = s u f f i x (x , s [ i ] ) ;
while ( x != t r i e && x−>n e x t [ c ] == 0 ) x = x−> f o r ( i n t j = 0 ; j < ( i n t ) x−>p a t s . s i z e ( ) ; j
fail ; ++) {
return ( x−>n e x t [ c ] ? x−>n e x t [ c ] : t r i e ) ; i d = x−>p a t s [ j ] ;
} ans . push_back ( i i ( id , i − s i z e s [ i d ] ) ) ;
public : }
AhoCorasick ( ) { t r i e = new node ( 0 ) ; s i z e = 1 ; } }
void c l e a r ( ) { return ans ;
node ∗x , ∗y ; }
queue<node∗> q ; q . push ( t r i e ) ;
while ( ! q . empty ( ) ) { //Dynamic Programming ( s i z e l e f t , appeared , node i d )
x = q . f r o n t ( ) ; q . pop ( ) ; private :
f o r ( i n t i = 0 ; i < ( i n t ) x−>a d j . s i z e ( ) ; i i n t dp [MAXK] [MAXK] [MAXN] ;
++) { i n l i n e i n t nOnes ( i n t mask ) {
y = x−>n e x t [ x−>a d j [ i ] ] ; i n t ans = 0 ;
i f ( y != NULL && y != t r i e ) q . push ( y ) ; while ( mask > 0 ) {
} ans++;
delete x ; mask −= ( mask & −mask ) ;
} }
t r i e = new node ( 0 ) ; s i z e = 1 ; return ans ;
} }
void s e t f a i l s ( ) { i n t DP( const i n t s , const i n t mask , node ∗ x ,
queue<node∗> q ; const i n t K) {
node ∗x , ∗y ; i f ( x == NULL) return 0 ;
f o r ( i n t i = 0 ; i < ALFA; i ++) { i f ( dp [ s ] [ mask ] [ x−>n i d ] >= 0 ) return dp [ s ] [
x = t r i e −>n e x t [ i ] ; mask ] [ x−>n i d ] ;
i f ( x != NULL && x != t r i e ) { i n t nmask = mask ;
x−> f a i l = t r i e ; f o r ( i n t i = 0 ; i < ( i n t ) x−>p a t s . s i z e ( ) ; i ++)
q . push ( x ) ; {
} nmask |= ( 1 << x−>p a t s [ i ] ) ;
} }
while ( ! q . empty ( ) ) {
CAPÍTULO 7. PROCESSAMENTO DE STRINGS 55

i f ( nOnes ( nmask ) > K) return dp [ s ] [ mask ] [ x−> i n t DP( i n t sz , i n t K) {


nid ] = 0 ; return DP( sz , 0 , t r i e , K) ;
i f ( s == 0 ) return dp [ s ] [ mask ] [ x−>n i d ] = 1 ; }
i n t ans = 0 ; void i ni t DP ( ) {
f o r ( char c = ’ a ’ ; c <= ’ z ’ ; c++) { f o r ( i n t i = 0 ; i < MAXK; i ++)
ans = ( ans + DP( s − 1 , nmask , s u f f i x ( x , c ) , f o r ( i n t j = 0 ; j < MAXK; j ++)
K) ) % MOD; f o r ( i n t s = 0 ; s < s i z e ; s++)
} dp [ i ] [ j ] [ s ] = −1;
return dp [ s ] [ mask ] [ x−>n i d ] = ans ; }
} };
public :

7.11 Longest Common Subsequence


Técnica com PD para calcular a maior subsequência comum a duas strings. Chamar DP (0, 0). O(n2 ), pode ser feito em
O(nlogn) com Suffix Array.

#include <c s t d i o > i f ( i==n ) return dp [ i ] [ j ] = DP( i , j +1) ;


#define MAXN 109 i f ( j==m) return dp [ i ] [ j ] = DP( i +1 , j ) ;
dp [ i ] [ j ] = DP( i +1 , j ) ;
i n t dp [MAXN] [MAXN] , n , m; i f (DP( i , j +1)>dp [ i ] [ j ] ) dp [ i ] [ j ]=dp [ i ] [ j + 1 ] ;
char s t r 1 [MAXN] , s t r 2 [MAXN] ; i f ( s t r 1 [ i ]== s t r 2 [ j ] && 1+DP( i +1 , j +1)>dp [ i ] [ j ] )
dp [ i ] [ j ]=1+dp [ i + 1 ] [ j + 1 ] ;
i n t DP( i n t i , i n t j ) { return dp [ i ] [ j ] ;
i f ( dp [ i ] [ j ]>=0) return dp [ i ] [ j ] ; }
i f ( i==n && j==m) return dp [ i ] [ j ] = 0 ;

7.12 Função Z e Algoritmo Z


Função Z é uma função tal que z[i] é máximo e str[j] = str[i + j], 0 ≤ j ≤ z[i]. O algoritmo Z computa todos os z[i],
0 ≤ i < n, em O(n). z[0] = 0.

#include <c s t d i o > i f ( i <= r )


#include <c s t r i n g > z [ i ] = min ( r−i +1 , z [ i −l ] ) ;
#include <a l g o r i t h m > while ( i+z [ i ] < n && s [ z [ i ] ] == s [ i+z [ i ] ] )
using namespace s t d ; ++z [ i ] ;
i f ( i+z [ i ] −1 > r )
void z f u n c t i o n ( char∗ s , i n t ∗ z ) { l = i, r = i+z [ i ] − 1 ;
int n = s t r l e n ( s ) ; }
f i l l ( z , z+n , 0 ) ; }
f o r ( i n t i =1 , l =0 , r =0; i <n ; ++i ) {
Capítulo 8

Geometria Computacional

8.1 Ponto 2D
Ponto com double em 2D com algumas funcionalidades: distância, produto interno, produto vetorial (componente z), teste
counter-clockwise, teste de pontos colineares, rotação em relação ao centro do plano, projeção de u sobre v.

#include <cmath> double i n n e r ( p o i n t p1 , p o i n t p2 ) {


#include <v e c t o r > return p1 . x∗ p2 . x + p1 . y∗ p2 . y ;
using namespace s t d ; }
#define EPS 1 e−9
double c r o s s ( p o i n t p1 , p o i n t p2 ) {
struct p o i n t { return p1 . x∗ p2 . y − p1 . y∗ p2 . x ;
double x , y ; }
point () { x = y = 0 . 0 ; }
p o i n t ( double _x , double _y) : x (_x) , y (_y) {} bool ccw ( p o i n t p , p o i n t q , p o i n t r ) {
double norm ( ) { return hypot ( x , y ) ; } return c r o s s ( q−p , r−p ) > 0 ;
point normalized () { }
return p o i n t ( x , y ) ∗ ( 1 . 0 / norm ( ) ) ;
} bool c o l l i n e a r ( p o i n t p , p o i n t q , p o i n t r ) {
double a n g l e ( ) { return atan2 ( y , x ) ; } return f a b s ( c r o s s ( p−q , r−p ) ) < EPS ;
double p o l a r A n g l e ( ) { }
double a = atan2 ( y , x ) ;
return a < 0 ? a + 2∗M_PI : a ; p o i n t r o t a t e ( p o i n t p , double rad ) {
} return p o i n t ( p . x ∗ c o s ( rad ) − p . y ∗ s i n ( rad ) ,
bool operator < ( p o i n t o t h e r ) const { p . x ∗ s i n ( rad ) + p . y ∗ c o s ( rad ) ) ;
i f ( f a b s ( x − o t h e r . x ) > EPS) }
return x < o t h e r . x ;
e l s e return y < o t h e r . y ; double a n g l e ( p o i n t a , p o i n t o , p o i n t b ) {
} return a c o s ( i n n e r ( a−o , b−o ) / ( d i s t ( o , a ) ∗ d i s t ( o , b
bool operator == ( p o i n t o t h e r ) const { )));
return ( f a b s ( x − o t h e r . x ) < EPS && ( f a b s ( y − }
o t h e r . y ) < EPS) ) ;
} point proj ( point u , point v){
p o i n t operator +( p o i n t o t h e r ) const { return v ∗ ( i n n e r ( u , v ) / i n n e r ( v , v ) ) ;
return p o i n t ( x + o t h e r . x , y + o t h e r . y ) ; }
}
p o i n t operator −( p o i n t o t h e r ) const { bool between ( p o i n t p , p o i n t q , p o i n t r ) {
return p o i n t ( x − o t h e r . x , y − o t h e r . y ) ; return c o l l i n e a r ( p , q , r ) && i n n e r ( p − q , r − q )
} <= 0 ;
p o i n t operator ∗ ( double k ) const { }
return p o i n t ( x∗k , y∗k ) ;
} i n t l e f t m o s t I n d e x ( v e c t o r <p o i n t > &P) {
}; i n t ans = 0 ;
f o r ( i n t i =1; i <( i n t )P . s i z e ( ) ; i ++){
double d i s t ( p o i n t p1 , p o i n t p2 ) { i f (P [ i ] < P [ ans ] ) ans = i ;
return hypot ( p1 . x − p2 . x , p1 . y − p2 . y ) ; }
} return ans ;
}

56
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 57

8.2 Linha 2D
Algumas funções de reta e segmento de reta no plano 2D: dois pontos para reta, projeção e distância ponto-reta e lonto-
segmento de reta. Reta representada da forma ax + by + c = 0. Se possivel fazemos b = 1.

struct l i n e { p . x = ( l2 . b ∗ l1 . c − l1 . b ∗ l2 . c ) / ( l2 . a ∗ l1 . b
double a , b , c ; − l1 . a ∗ l2 . b) ;
l i n e ( ) { a = b = c = NAN; } i f ( f a b s ( l 1 . b ) > EPS) p . y = −( l 1 . a ∗ p . x + l 1 . c ) ;
l i n e ( double _a , double _b , double _c ) : a (_a) , b ( e l s e p . y = −( l 2 . a ∗ p . x + l 2 . c ) ;
_b) , c ( _c ) {} return p ;
}; }

l i n e p o i n t s T o L i n e ( p o i n t p1 , p o i n t p2 ) { point projPointToLine ( point u , l i n e l ) {


line l ; point a , b ;
i f ( f a b s ( p1 . x − p2 . x ) < EPS && f a b s ( p1 . y − p2 . y ) i f ( f a b s ( l . b − 1 . 0 ) < EPS) {
< EPS) { a = p o i n t (− l . c / l . a , 0 . 0 ) ;
l . a = l . b = l . c = NAN; b = p o i n t (− l . c / l . a , 1 . 0 ) ;
} }
e l s e i f ( f a b s ( p1 . x − p2 . x ) < EPS) { else {
l . a = 1 . 0 ; l . b = 0 . 0 ; l . c = −p1 . x ; a = point (0 , −l . c / l . b) ;
} b = p o i n t ( 1 , −( l . c + 1 . 0 ) / l . b ) ;
else { }
l . a = −(p1 . y − p2 . y ) / ( p1 . x − p2 . x ) ; return a + p r o j ( u − a , b − a ) ;
l .b = 1.0; }
l . c = −( l . a ∗ p1 . x ) − p1 . y ;
} double d i s t T o L i n e ( p o i n t p , l i n e l ) {
return l ; return d i s t ( p , p r o j P o i n t T o L i n e ( p , l ) ) ;
} }

bool a r e P a r a l l e l ( l i n e l 1 , l i n e l 2 ) { point closestToLineSegment ( point p , point a , point b


return ( f a b s ( l 1 . a − l 2 . a ) < EPS) && ( f a b s ( l 1 . b − ) {
l 2 . b ) < EPS) ; double u = i n n e r ( p−a , b−a ) / i n n e r ( b−a , b−a ) ;
} i f ( u < 0 . 0 ) return a ;
bool areSame ( l i n e l 1 , l i n e l 2 ) { i f ( u > 1 . 0 ) return b ;
return a r e P a r a l l e l ( l 1 , l 2 ) && ( f a b s ( l 1 . c − l 2 . c ) return a + ( ( b − a ) ∗u ) ;
< EPS) ; }
}
double d i s t T o L i n e S e g m e n t ( p o i n t p , p o i n t a , p o i n t b )
point i n t e r s e c t i o n ( l i n e l1 , l i n e l 2 ) { {
i f ( a r e P a r a l l e l ( l 1 , l 2 ) ) return p o i n t (NAN, NAN) ; return d i s t ( p , c l o s e s t T o L i n e S e g m e n t ( p , a , b ) ) ;
point p ; }

8.3 Círculo 2D
struct c i r c l e { p o i n t u = p o i n t ( ( b−a ) . y , −(b−a ) . x ) ;
point c ; p o i n t v = p o i n t ( ( c−a ) . y , −(c−a ) . x ) ;
double r ; p o i n t n = ( c−b ) ∗ 0 . 5 ;
c i r c l e () { c = point () ; r = 0; } double t = c r o s s ( u , n ) / c r o s s ( v , u ) ;
c i r c l e ( p o i n t _c , double _r ) : c ( _c ) , r ( _r ) {} ans . c = ( ( a+c ) ∗ 0 . 5 ) + ( v∗ t ) ;
double a r e a ( ) { return M_PI∗ r ∗ r ; } ans . r = d i s t ( ans . c , a ) ;
double chord ( double rad ) { return 2∗ r ∗ s i n ( rad return ans ;
/2.0) ; } }
double s e c t o r ( double rad ) { return 0 . 5 ∗ rad ∗ a r e a ( )
/M_PI ; } int i n s i d e C i r c l e ( point p , c i r c l e c ) {
bool i n t e r s e c t s ( c i r c l e o t h e r ) { i f ( f a b s ( d i s t ( p , c . c ) − c . r )<EPS) return 1 ;
return d i s t ( c , o t h e r . c ) < r + o t h e r . r ; e l s e i f ( d i s t ( p , c . c ) < c . r ) return 0 ;
} e l s e return 2 ;
bool c o n t a i n s ( p o i n t p ) { return d i s t ( c , p ) <= r + } // 0 = i n s i d e /1 = b o r d e r /2 = o u t s i d e
EPS ; }
bool i s E n c l o s i n g C i r c l e ( v e c t o r <p o i n t > & p , i n t n ) { c i r c l e i n c i r c l e ( p o i n t p1 , p o i n t p2 , p o i n t p3 ) {
f o r ( i n t i =0; i <n ; i ++){ double m1=d i s t ( p2 , p3 ) ;
i f ( ! c o n t a i n s ( p [ i ] ) ) return f a l s e ; double m2=d i s t ( p1 , p3 ) ;
} double m3=d i s t ( p1 , p2 ) ;
return true ; p o i n t c = ( p1 ∗m1+p2 ∗m2+p3 ∗m3) ∗ ( 1 / (m1+m2+m3) ) ;
} double s = 0 . 5 ∗ ( m1+m2+m3) ;
}; double r = s q r t ( s ∗ ( s−m1) ∗ ( s−m2) ∗ ( s−m3) ) / s ;
return c i r c l e ( c , r ) ;
c i r c l e circumcircle ( point a , point b , point c ){ }
c i r c l e ans ;
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 58

8.4 Triângulo 2D
struct t r i a n g l e { return c i r c u m c i r c l e ( a , b , c ) ;
point a , b , c ; }
t r i a n g l e () { a = b = c = point () ; } int i s I n s i d e ( point p ) {
t r i a n g l e ( p o i n t _a , p o i n t _b , p o i n t _c ) : a (_a) , b double u = c r o s s ( b−a , p−a ) ∗ c r o s s ( b−a , c−a ) ;
(_b) , c ( _c ) {} double v = c r o s s ( c−b , p−b ) ∗ c r o s s ( c−b , a−b ) ;
double p e r i m e t e r ( ) { return d i s t ( a , b ) + d i s t ( b , c ) double w = c r o s s ( a−c , p−c ) ∗ c r o s s ( a−c , b−c ) ;
+ dist (c , a) ; } i f ( u > 0 . 0 && v > 0 . 0 && w > 0 . 0 ) return 0 ;
double s e m i P e r i m e t e r ( ) { return p e r i m e t e r ( ) / 2 . 0 ; i f ( u < 0 . 0 | | v < 0 . 0 | | w < 0 . 0 ) return 2 ;
} e l s e return 1 ;
double a r e a ( ) { } // 0 = i n s i d e / 1 = b o r d e r / 2 = o u t s i d e
double s = s e m i P e r i m e t e r ( ) , ab = d i s t ( a , b ) , };
bc = d i s t ( b , c ) , ca = d i s t ( c , a ) ;
return s q r t ( s ∗ ( s−ab ) ∗ ( s−bc ) ∗ ( s−ca ) ) ; double r I n C i r c l e ( p o i n t a , p o i n t b , p o i n t c ) {
} return t r i a n g l e ( a , b , c ) . r I n C i r c l e ( ) ;
double r I n C i r c l e ( ) { }
return a r e a ( ) / s e m i P e r i m e t e r ( ) ;
} double r C i r c u m C i r c l e ( p o i n t a , p o i n t b , p o i n t c ) {
c i r c l e inCircle () { return t r i a n g l e ( a , b , c ) . r C i r c u m C i r c l e ( ) ;
return i n c i r c l e ( a , b , c ) ; }
}
double r C i r c u m C i r c l e ( ) { int i s I n s i d e T r i a n g l e ( point a , point b , point c ,
return d i s t ( a , b ) ∗ d i s t ( b , c ) ∗ d i s t ( c , a ) / ( 4 . 0 ∗ a r e a point p){
() ) ; return t r i a n g l e ( a , b , c ) . i s I n s i d e ( p ) ;
} } // 0 = i n s i d e / 1 = b o r d e r / 2 = o u t s i d e
c i r c l e circumCircle () {

8.5 Polígono 2D
Algumas funcionalidades do polígono 2D. IMPORTANTE: o último ponto de P é igual ao primeiro.

#include <v e c t o r > return f a l s e ;


#include <a l g o r i t h m > }
using namespace s t d ; return true ;
}
p o i n t l i n e I n t e r s e c t S e g ( p o i n t p , p o i n t q , p o i n t A, bool i n P o l y g o n ( p o l y g o n & P , p o i n t p ) {
p o i n t B) { i f (P . s i z e ( ) == 0u ) return f a l s e ;
double a = B . y − A. y ; double sum = 0 . 0 ;
double b = A. x − B . x ; f o r ( i n t i = 0 ; i < ( i n t )P . s i z e ( ) −1; i ++) {
double c = B . x ∗ A. y − A. x ∗ B . y ; i f ( ccw ( p , P [ i ] , P [ i +1]) ) sum += a n g l e (P [ i ] , p
double u = f a b s ( a ∗ p . x + b ∗ p . y + c ) ; , P [ i +1]) ;
double v = f a b s ( a ∗ q . x + b ∗ q . y + c ) ; e l s e sum −= a n g l e (P [ i ] , p , P [ i +1]) ;
return p o i n t ( ( p . x ∗ v + q . x ∗ u ) / ( u+v ) , ( p . y ∗ }
v + q . y ∗ u ) / ( u+v ) ) ; return f a b s ( f a b s ( sum ) − 2∗M_PI) < EPS ;
} }
p o l y g o n make_polygon ( v e c t o r <p o i n t > P) {
typedef v e c t o r <p o i n t > p o l y g o n ; i f ( ! P . empty ( ) && ! ( P . back ( ) == P . f r o n t ( ) ) )
P . push_back (P [ 0 ] ) ;
double p e r i m e t e r ( p o l y g o n & P) { i f ( s i g n e d A r e a (P) < 0 . 0 ) {
double r e s u l t = 0 . 0 ; f o r ( i n t i = 0 ; 2∗ i < ( i n t )P . s i z e ( ) ; i ++){
f o r ( i n t i = 0 ; i < ( i n t )P . s i z e ( ) −1; i ++) r e s u l t swap (P [ i ] , P [ P . s i z e ( )−i −1]) ;
+= d i s t (P [ i ] , P [ i +1]) ; }
return r e s u l t ; }
} return P ;
double s i g n e d A r e a ( p o l y g o n & P) { }
double r e s u l t = 0 . 0 ; polygon cutPolygon ( polygon P, point a , point b ) {
f o r ( i n t i = 0 ; i < ( i n t )P . s i z e ( ) −1; i ++) { v e c t o r <p o i n t > R;
r e s u l t += c r o s s (P [ i ] , P [ i +1]) ; double l e f t 1 , l e f t 2 ;
} f o r ( i n t i = 0 ; i < ( i n t )P . s i z e ( ) ; i ++) {
return r e s u l t / 2 . 0 ; l e f t 1 = c r o s s ( b−a , P [ i ]−a ) ;
} i f ( i != ( i n t )P . s i z e ( ) −1) l e f t 2 = c r o s s ( b−a , P
double a r e a ( p o l y g o n & P) { [ i +1]−a ) ;
return f a b s ( s i g n e d A r e a (P) ) ; else l e f t 2 = 0;
} i f ( l e f t 1 > −EPS) P . push_back (P [ i ] ) ;
bool i s C o n v e x ( p o l y g o n & P) { i f ( l e f t 1 ∗ l e f t 2 < −EPS)
i n t s z = ( i n t )P . s i z e ( ) ; R. push_back ( l i n e I n t e r s e c t S e g (P [ i ] , P [ i + 1 ] ,
i f ( s z <= 3 ) return f a l s e ; a , b) ) ;
bool i s L e f t = ccw (P [ 0 ] , P [ 1 ] , P [ 2 ] ) ; }
f o r ( i n t i = 1 ; i < sz −1; i ++){ return make_polygon (R) ;
i f ( ccw (P [ i ] , P [ i + 1 ] , P [ ( i +2) == s z ? 1 : i }
+2]) != i s L e f t )
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 59

8.6 Convex Hull


Dado um conjunto de pontos, retorna o menor polígono que contém todos os pontos. Retorna o primeiro ponto repetido.

#include <a l g o r i t h m > }


using namespace s t d ; i n t P0 = l e f t m o s t I n d e x (P) ;
swap (P [ 0 ] , P [ P0 ] ) ;
point pivot (0 , 0) ; pivot = P [ 0 ] ;
s o r t (++P . b e g i n ( ) , P . end ( ) , angleCmp ) ;
bool angleCmp ( p o i n t a , p o i n t b ) { v e c t o r <p o i n t > S ;
i f ( c o l l i n e a r ( p i v o t , a , b ) ) return d i s t ( p i v o t , a ) S . push_back (P [ n −1]) ;
< d i s t ( pivot , b) ; S . push_back (P [ 0 ] ) ;
double d1x = a . x−p i v o t . x , d1y = a . y−p i v o t . y ; S . push_back (P [ 1 ] ) ;
double d2x = b . x−p i v o t . x , d2y = b . y−p i v o t . y ; i = 2;
return atan2 ( d1y , d1x ) − atan2 ( d2y , d2x ) < 0 ; while ( i < n ) {
} j = ( i n t ) S . s i z e ( ) −1;
i f ( ccw ( S [ j − 1 ] , S [ j ] , P [ i ] ) ) S . push_back (P [ i
v e c t o r <p o i n t > c o n v e x H u l l ( v e c t o r <p o i n t > P) { ++]) ;
i n t i , j , n = ( i n t )P . s i z e ( ) ; e l s e S . pop_back ( ) ;
i f ( n <= 3 ) { }
i f ( ! ( P [ 0 ] == P [ n −1]) ) P . push_back (P [ 0 ] ) ; return S ;
return P ; }

8.7 Ponto dentro de polígono convexo


Dado um polígono convexo com o primeiro ponto igual ao último e um novo ponto q, verifica se o ponto está dentro (inclui
borda) em O(logn). O ponto índice 1 (pivot) deve ser um pivô válido para não quebrar atan2. Pode usar o vector retornado
direto da função convexHull.

bool query ( v e c t o r <p o i n t > &CH, p o i n t q ) { e l s e i = m;


i n t i = 2 , j = CH. s i z e ( ) −1, m; }
p i v o t = CH [ 1 ] ; return i s I n s i d e T r i a n g l e ( p i v o t , CH[ i ] , CH[ j ] , q )
while ( j > i +1){ != 2 ;
i n t m = ( i+j ) / 2 ; }
i f ( angleCmp ( q , CH[m] ) ) j = m;

8.8 Soma de Minkowski


Determina o polígono que contorna a soma de Minkowski de duas regiões delimitadas por polígonos regulares. A soma de
Minkowski de dois conjuntos de pontos A e B é o conjunto C = {u ∈ R2 |u = a + b, a ∈ A, b ∈ B}. Algumas aplicações
interessantes:

• Para verificar se A e B possuem intersecção, basta verificar se (0, 0) ∈ minkowski(A, −B).


• (1/n) ∗ minkowski(A1 , A2 , ..., An ) representa todos os baricentros possíveis de pontos em A1 , A2 , ..., An .

p o l y g o n minkowski ( p o l y g o n A, p o l y g o n B) { }
polygon P; e l s e i f ( c1 == n1 | | ( c2 < n2 && c r o s s ( v1 , v2 )
A. pop_back ( ) ; B . pop_back ( ) ; < 0) ) {
i n t s 1 = l e f t m o s t I n d e x (A) , n1 = A. s i z e ( ) ; P . push_back (P . back ( ) + v2 ) ;
i n t s 2 = l e f t m o s t I n d e x (B) , n2 = B . s i z e ( ) ; j = ( j +1)%n2 ; c2++;
P . push_back (A[ s 1 ]+B [ s 2 ] ) ; }
i n t i=s 1 +1 , j=s 2 +1 , c1 =0 , c2 =0; else {
p o i n t v1 , v2 ; P . push_back (P . back ( ) + ( v1+v2 ) ) ;
while ( c1 < n1 | | c2 < n2 ) { i = ( i +1)%n1 ; c1++;
v1 = A[ i ]−A [ ( i −1+n1 )%n1 ] ; j = ( j +1)%n2 ; c2++;
v2 = B [ j ]−B [ ( j −1+n2 )%n2 ] ; }
i f ( c2 == n2 | | ( c1 < n1 && c r o s s ( v1 , v2 ) > 0 ) }
){ return make_polygon (P) ;
P . push_back (P . back ( ) + v1 ) ; }
i = ( i +1)%n1 ; c1++;
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 60

8.9 Minimum Enclosing Circle


Computa o círculo de raio mínimo que contém um conjunto de pontos. Baseado em permutação aleatória. Complexidade:
expected O(n).

c i r c l e minimumCircle ( v e c t o r <p o i n t > p ) { f o r ( i n t k = 0 ; k < j ; k++){


r a n d o m _ s h u f f l e ( p . b e g i n ( ) , p . end ( ) ) ; i f (C . c o n t a i n s ( p [ k ] ) ) continue ;
c i r c l e C = c i r c l e (p [ 0 ] , 0.0) ; C = circumcircle (p [ j ] , p [ i ] , p [ k ] ) ;
f o r ( i n t i = 0 ; i < ( i n t ) p . s i z e ( ) ; i ++){ }
i f (C . c o n t a i n s ( p [ i ] ) ) continue ; }
C = c i r c l e (p [ i ] , 0.0) ; }
f o r ( i n t j = 0 ; j < i ; j ++){ return C ;
i f (C . c o n t a i n s ( p [ j ] ) ) continue ; }
C = c i r c l e (( p [ j ] + p [ i ] ) ∗0.5 , 0.5∗ dist (p [ j
] , p[ i ]) ) ;

8.10 Ponto inteiro


Algumas funções de ponto usando apenas inteiros: insideCircle e o comparador polar polarCmp para x, y > 109 .

typedef long long l l ; ll c r o s s ( point_i a , point_i b) {


return a . x∗b . y − a . y∗b . x ;
struct p o i n t _ i { }
ll x, y; int i n s i d e C i r c l e ( point_i p , point_i c , int r ) {
point_i ( ) { x = y = 0; } l l dx = p . x − c . x , dy = p . y − c . y ;
p o i n t _ i ( l l _x , l l _y) : x (_x) , y (_y) {} l l Euc = dx ∗ dx + dy ∗ dy , rSq = r ∗ r ;
bool operator < ( p o i n t _ i o t h e r ) const { return Euc < rSq ? 0 : Euc == rSq ? 1 : 2 ;
i f ( x != o t h e r . x ) return x < o t h e r . x ; } // 0 = i n s i d e /1 = b o r d e r /2 = o u t s i d e
e l s e return y < o t h e r . y ; bool polarCmp ( p o i n t _ i a , p o i n t _ i b ) {
} i f ( b . y∗ a . y > 0 ) return c r o s s ( a , b ) > 0 ;
bool operator == ( p o i n t _ i o t h e r ) const { e l s e i f ( b . y == 0 && b . x > 0 ) return f a l s e ;
return ( x == o t h e r . x && y == o t h e r . y ) ; e l s e i f ( a . y == 0 && a . x > 0 ) return true ;
} e l s e return b . y < a . y ;
}; }

8.11 Ponto 3D
#include <c s t d i o > return p o i n t ( x − o t h e r . x , y − o t h e r . y , z −
#include <cmath> other . z ) ;
#define EPS 1 e−9 }
p o i n t operator ∗ ( double k ) const {
struct p o i n t { return p o i n t ( x∗k , y∗k , z ∗k ) ;
double x , y , z ; }
point () { x = y = z = 0 . 0 ; } };
p o i n t ( double _x , double _y , double _z ) : x (_x) , y double d i s t ( p o i n t p1 , p o i n t p2 ) {
(_y) , z ( _z ) {} return ( p1−p2 ) . norm ( ) ;
double norm ( ) { return hypot ( x , y , z ) ; } }
point normalized () { double i n n e r ( p o i n t p1 , p o i n t p2 ) {
return p o i n t ( x , y , z ) ∗ ( 1 . 0 / norm ( ) ) ; return p1 . x∗ p2 . x + p1 . y∗ p2 . y + p1 . z ∗ p2 . z ;
} }
bool operator < ( p o i n t o t h e r ) const { p o i n t c r o s s ( p o i n t p1 , p o i n t p2 ) {
i f ( f a b s ( x − o t h e r . x ) > EPS) return x < o t h e r . p o i n t ans ;
x; ans . x = p1 . y∗ p2 . z − p1 . z ∗ p2 . y ;
e l s e i f ( f a b s ( y − o t h e r . y ) > EPS) return y < ans . y = p1 . z ∗ p2 . x − p1 . x∗ p2 . z ;
other . y ; ans . z = p1 . x∗ p2 . y − p1 . y∗ p2 . x ;
e l s e return z < o t h e r . z ; return ans ;
} }
bool operator == ( p o i n t o t h e r ) const { bool c o l l i n e a r ( p o i n t p , p o i n t q , p o i n t r ) {
return ( f a b s ( x − o t h e r . x ) < EPS && f a b s ( y − return c r o s s ( p−q , r−p ) . norm ( ) < EPS ;
o t h e r . y ) < EPS && f a b s ( z − o t h e r . z ) < EPS) }
; double a n g l e ( p o i n t a , p o i n t o , p o i n t b ) {
} return a c o s ( i n n e r ( a−o , b−o ) / ( d i s t ( o , a ) ∗ d i s t ( o , b
p o i n t operator +( p o i n t o t h e r ) const { )));
return p o i n t ( x + o t h e r . x , y + o t h e r . y , z + }
other . z ) ; point proj ( point u , point v){
} return v ∗ ( i n n e r ( u , v ) / i n n e r ( v , v ) ) ;
p o i n t operator −( p o i n t o t h e r ) const { }
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 61

8.12 Triângulo 3D
struct t r i a n g l e { double v = p r o j ( c r o s s ( c−b , p−b ) , n ) . n o r m a l i z e d
point a , b , c ; ( ) ∗ p r o j ( c r o s s ( c−b , a−b ) , n ) . n o r m a l i z e d ( ) ;
t r i a n g l e () { a = b = c = point () ; } double w = p r o j ( c r o s s ( a−c , p−c ) , n ) . n o r m a l i z e d
t r i a n g l e ( p o i n t _a , p o i n t _b , p o i n t _c ) : a (_a) , b ( ) ∗ p r o j ( c r o s s ( a−c , b−c ) , n ) . n o r m a l i z e d ( ) ;
(_b) , c ( _c ) {} i f ( u > 0 . 0 && v > 0 . 0 && w > 0 . 0 ) return 0 ;
double p e r i m e t e r ( ) { return d i s t ( a , b ) + d i s t ( b , c ) e l s e i f ( u < 0 . 0 | | v < 0 . 0 | | w < 0 . 0 ) return
+ dist (c , a) ; } 2;
double s e m i P e r i m e t e r ( ) { return p e r i m e t e r ( ) / 2 . 0 ; e l s e return 1 ;
} } // 0 = i n s i d e / 1 = b o r d e r / 2 = o u t s i d e
double a r e a ( ) { int i s P r o j I n s i d e ( point p ) {
double s = s e m i P e r i m e t e r ( ) , ab = d i s t ( a , b ) , return i s I n s i d e ( p + p r o j ( a−p , n o r m a l V e c t o r ( ) ) )
bc = d i s t ( b , c ) , ca = d i s t ( c , a ) ; ;
return s q r t ( s ∗ ( s−ab ) ∗ ( s−bc ) ∗ ( s−ca ) ) ; } // 0 = i n s i d e / 1 = b o r d e r / 2 = o u t s i d e
} };
double r I n C i r c l e ( ) {
return a r e a ( ) / s e m i P e r i m e t e r ( ) ; double r I n C i r c l e ( p o i n t a , p o i n t b , p o i n t c ) {
} return t r i a n g l e ( a , b , c ) . r I n C i r c l e ( ) ;
double r C i r c u m C i r c l e ( ) { }
return d i s t ( a , b ) ∗ d i s t ( b , c ) ∗ d i s t ( c , a ) / ( 4 . 0 ∗ a r e a
() ) ; double r C i r c u m C i r c l e ( p o i n t a , p o i n t b , p o i n t c ) {
} return t r i a n g l e ( a , b , c ) . r C i r c u m C i r c l e ( ) ;
point normalVector ( ) { }
return c r o s s ( y−x , z−x ) . n o r m a l i z e d ( ) ;
} int i s P r o j I n s i d e T r i a n g l e ( point a , point b , point c ,
int i s I n s i d e ( point p) { point p){
point n = normalVector ( ) ; return t r i a n g l e ( a , b , c ) . i s P r o j I n s i d e ( p ) ;
double u = p r o j ( c r o s s ( b−a , p−a ) , n ) . n o r m a l i z e d } // 0 = i n s i d e / 1 = b o r d e r / 2 = o u t s i d e
( ) ∗ p r o j ( c r o s s ( b−a , c−a ) , n ) . n o r m a l i z e d ( ) ;

8.13 Linha 3D
Desta vez a linha é implementada com um ponto de referência e um vetor base. distV ector é um vetor que é perpendicular a
ambas as linhas e tem como comprimento a distância entre elas. distV ector é a "ponte"de a a b de menor caminho entre as
duas linhas. distV ectorBaseP oint é o ponto da linha a de onde sai o distV ector. distV ectorEndP oint é o ponto na linha
b onde chega a ponte.

struct l i n e { }
point r ; e l s e return p r o j ( dr , n ) ;
point v ; }
l i n e ( p o i n t _r , p o i n t _v) {
v = _v ; r = _r ; double d i s t ( l i n e a , l i n e b ) {
} return d i s t V e c t o r ( a , b ) . norm ( ) ;
bool operator == ( l i n e o t h e r ) const { }
return f a b s ( c r o s s ( r−o t h e r . r , v ) . norm ( ) ) <
EPS && f a b s ( c r o s s ( r−o t h e r . r , o t h e r . v ) . point distVectorBasePoint ( l i n e a , l i n e b){
norm ( ) ) < EPS ; i f ( c r o s s ( a . v , b . v ) . norm ( ) < EPS) return a . r ;
} point d = distVector (a , b) ;
}; double lambda ;
i f ( f a b s ( b . v . x∗ a . v . y − a . v . x∗b . v . y ) > EPS)
point distVector ( l i n e l , point p){ lambda = ( b . v . x ∗ ( b . r . y−a . r . y−d . y ) − b . v . y ∗ ( b
p o i n t dr = p − l . r ; . r . x−a . r . x−d . x ) ) / ( b . v . x∗ a . v . y − a . v . x∗b .
return dr − p r o j ( dr , l . v ) ; v . y) ;
} e l s e i f ( f a b s ( b . v . x∗ a . v . z − a . v . x∗b . v . z ) > EPS)
lambda = ( b . v . x ∗ ( b . r . z−a . r . z−d . z ) − b . v . z ∗ ( b
point distVectorBasePoint ( l i n e l , point p){ . r . x−a . r . x−d . x ) ) / ( b . v . x∗ a . v . z − a . v . x∗b .
return p r o j ( p − l . r , l . v ) + l . r ; v.z) ;
} e l s e i f ( f a b s ( b . v . z ∗ a . v . y − a . v . z ∗b . v . y ) > EPS)
lambda = ( b . v . z ∗ ( b . r . y−a . r . y−d . y ) − b . v . y ∗ ( b
point distVectorEndPoint ( l i n e l , point p) { . r . z−a . r . z−d . z ) ) / ( b . v . z ∗ a . v . y − a . v . z ∗b .
return p ; v . y) ;
} return a . r + ( a . v∗ lambda ) ;
}
point distVector ( l i n e a , l i n e b){
p o i n t dr = b . r − a . r ; point distVectorEndPoint ( l i n e a , l i n e b) {
point n = cross (a . v , b . v) ; return d i s t V e c t o r B a s e P o i n t ( a , b ) + d i s t V e c t o r ( a ,
i f ( n . norm ( ) < EPS) { b) ;
return dr − p r o j ( dr , a . v ) ; }
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 62

8.14 Grande Círculo


Dado o raio da Terra e as coordenadas em latitude e longitude de dois pontos p e q, retorna o ângulo pOq. Retorna a
distância mínima de viagem pela superfície.

#include <c s t d i o > c o s ( pLat ) ∗ s i n ( pLong ) ∗ c o s ( qLat ) ∗ s i n ( qLong ) +


#include <cmath> s i n ( pLat ) ∗ s i n ( qLat ) ) ;
}
double gcTheta ( double pLat , double pLong , double
qLat , double qLong ) { double g c D i s t a n c e ( double pLat , double pLong , double
pLat ∗= PI / 1 8 0 . 0 ; pLong ∗= PI / 1 8 0 . 0 ; // qLat , double qLong , double r a d i u s ) {
convert degree to radian return r a d i u s ∗ gcTheta ( pLat , pLong , qLat , qLong ) ;
qLat ∗= PI / 1 8 0 . 0 ; qLong ∗= PI / 1 8 0 . 0 ; }
return a c o s ( c o s ( pLat ) ∗ c o s ( pLong ) ∗ c o s ( qLat ) ∗ c o s (
qLong ) +

8.15 Coordenadas polares, cilíndricas e esféricas


Coordenadas polares: Coordenadas esféricas:

x = rcosφ y = rsenφ dS = rdrdφ (8.1) x = rcosφsenθ y = rsenφsenθ z = rcosθ (8.8)


Coordenadas cilíndricas: ~ = drr̂ + rdθθ̂ + rsenθdφφ̂
dγ (8.9)
x = rcosφ y = rsenφ z=z (8.2) ~ r = r2 senθdθdφr̂
dS ~ θ = rsenθdφdrθ̂
dS ~ φ = rdrdθφ̂
dS
~ = drr̂ + rdφφ̂ + dz ẑ (8.10)
dγ dV = rdrdφdz (8.3) dSr
dV = r2 senθdrdθdφ dΩ == senθdθdφ (8.11)
~ r = rdφdzr̂
dS ~ φ = drdz φ̂
dS ~ z = rdrdφẑ
dS (8.4) r2

~ = ∂f r̂ + 1 ∂f θ̂ + ∂f ẑ ~ = ∂f r̂ + 1 ∂f θ̂ + 1 ∂f φ̂
∇f (8.12)
∇f (8.5) ∂r r ∂θ rsenθ ∂φ
∂r r ∂φ ∂z
~ F~ = 1 ∂ (rFr ) + 1 ∂Fφ + ∂Fz
∇. (8.6) ~ F~ = 1 ∂ (r2 Fr )+ 1 ∂ (senθFθ )+ 1 ∂Fφ (8.13)
∇.
r ∂r r ∂φ ∂z r2 ∂r rsenθ ∂θ rsenθ ∂φ

~ × F~ = ( 1 ∂Fz − ∂Fφ )r̂+


∇ ~ × F~ =

1 ∂
( (Fφ senθ) −
∂Fθ
)r̂+
r ∂φ ∂z rsenθ ∂θ ∂φ
(8.7) (8.14)
∂Fr ∂Fz 1 ∂ ∂Fr 1 1 ∂Fr ∂ 1 ∂ ∂Fr
( − )φ̂ + ( (rFφ ) − )ẑ ( − (rFφ ))θ̂ + ( (rFθ ) − )φ̂
∂z ∂r r ∂r ∂φ r senθ ∂φ ∂r r ∂r ∂θ

8.16 Cálculo Vetorial 2D


Curva regular no plano e comprimento do arco: 1 ~ (t)
N
R(t) = ~
C(t) = ~γ (t) + (8.21)
Z b |k(t)| K(t)
~γ (t), C 1 , ~γ 0 (t) 6= 0 L(γ) = ||~γ 0 (t)||dt (8.15)
a

Reta tangente e normal: Equações de Frenet:

T : X = ~γ (t0 ) + λ.~γ 0 (t0 ) (8.16)


T~ 0 (t) = K(s).N
~ (t) ~ 0 (t) = −K(t).T~ (t)
N (8.22)
2 0
N : {X ∈ R :< X − ~γ (t0 ), ~γ (t0 ) >= 0} (8.17)
Curva de orientação invertida: Teorema de Gauss no plano:
~γ − (t) = ~γ (a + b − t) (8.18)
Z Z Z
Referencial de Frenet: F~ .N
~ dγ = ~ F~ dxdy
∇. (8.23)
~γ 0 (t) ∂S S
T~ (t) = ~ (t) = (−Ty (t), Tx (t))
N (8.19)
||~γ 0 (t)||
Teorema de Green:
Curvatura, raio e centro de curvatura:
~γ 00 (t).N~ (t) Z Z Z
∂Q ∂P
K(t) = (8.20) P dx + Qdy = ( − )dxdy (8.24)
||~γ 0 (t)||2 ∂Ω Ω ∂x ∂y
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 63

8.17 Cálculo Vetorial 3D


Referencial de Frenet: Superfície parametrizada:
~γ 0 (t) ~γ 0 (t) × ~γ 00 (t) ~ v) = (x(u, v), y(u, v), z(u, v))
S(u, (8.38)
T~ (t) = ~
B(t) = ~ (t) = B(t)×
N ~ T~ (t)
||~γ 0 (t)|| ||~γ 0 (t) × ~γ 00 (t)||
(8.25) ∂x ∂y ∂z ∂x ∂y ∂z
S~u (u, v) = ( , , ), S~v (u, v) = ( , , ) (8.39)
Curvatura e torção: ∂u ∂u ∂u ∂v ∂v ∂v
Vetor normal à superfície:
< ~γ 0 (t) × ~γ 00 (t), ~γ 000 (t) > ||~γ 0 (t) × ~γ 00 (t)||
τ (t) = K(t) =
||~γ 0 (t) × ~γ 00 (t)||2 ||~γ 0 (t)||3 ~ (u, v) = (S~u × S~v )(u, v) 6= ~0
N (8.40)
(8.26)
Plano normal a ~γ (t0 ): Superfície diferenciável:

< X − ~γ (t0 ), T (t0 ) >= 0 (8.27) ~ (u, v) 6= ~0


N (8.41)

Equações de Frenet: Plano tangente à superfície:

T~ 0 (t) = K(t).N
~ (t) (8.28) ~ 0 , v0 ), N
< (x, y, z) − S(u ~ (u0 , v0 ) >= 0 (8.42)
~ 0 (t) = −K(t).T~ (t) − τ (t).B(t)
N ~ (8.29) Área da superfície:
~ 0 (t) = −τ (t).N
B ~ (t) (8.30)
Z Z
A(S) = ~ (u, v)||dudv
||N (8.43)
Integral de linha de um campo escalar: U

Z Z b Integral de superfície de um campo escalar:


f dγ = f (~γ (t))||~γ 0 (t)||dt (8.31) Z Z Z Z
γ a
f dS = ~ v))||N
f (S(u, ~ (u, v)||dudv (8.44)
S U
Integral de linha de um campo vetorial:
Integral de superfície de um campo vetorial:
Z Z b
~γ =
F~ .d~ f~(~γ (t)).~γ (t)dt
0
(8.32) Z Z Z Z
γ a ~ ~
F .dS = F~ (S(u,
~ v)).N
~ (u, v)dudv (8.45)
S U
Operador nabla:
Massa e centro de massa:
~ =( ∂ , ∂ , ∂ )
∇ (8.33)
∂x ∂y ∂z Z Z
M= ρ(t)d~γ , xM = ~x(t)ρ(t)d~γ (8.46)
Campo gradiente: γ γ

~ (x, y, z) = ( ∂f , ∂f , ∂f )(x, y, z)
Z Z Z Z
F~ (x, y, z) = ∇f (8.34) M= ρ(u, v)ds xM = ~x(u, v)ρ(u, v)ds (8.47)
∂x ∂y ∂z S S
Z Z Z Z Z
Campo conservativo: M= ρ(x, y, z)dv xM = ~x(x, y, z)ρ(z, y, z)dv
Z V S
F~ (x, y, z) = ∇f
~ (x, y, z) ⇔ F~ .d~γ = 0 (8.35) (8.48)
γ Teorema de Pappus para a área, d = distância entre x e o
eixo de rotação:
Campo rotacional: A(S) = 2πdL(C) (8.49)

~ × F~ = ( ∂R − ∂Q , ∂P − ∂R , ∂Q − ∂P )
∇ (8.36)
Teorema de Pappus para o volume, d = distância entre x e o
∂y ∂z ∂z ∂x ∂x ∂y eixo de rotação:
V (Ω) = 2πdA(S) (8.50)
F~ é conservativo → ∇
~ × F~ = 0 Campo divergente:
Teorema de Gauss no espaço:
~ F~ = ( ∂P , ∂Q , ∂R )
∇. (8.37)
Z Z Z Z Z
∂x ∂y ∂z ~ ~
F .N dγ = ~ F~ dxdydz
∇. (8.51)
∂V V

• F~ é solenoidal quando ∇.~ F~ = 0


Teorema de Stokes:
• Existe G ~ tal que F~ = ∇
~ ×G ~ ⇒ ∇.
~ F~ = 0 Z Z Z
~ F~ 6= 0 ⇒ não existe G
• ∇. ~ tal que F~ = ∇
~ ×G
~ F~ .d~γ = ~ × F~ .N
∇ ~ ds (8.52)
∂S S
CAPÍTULO 8. GEOMETRIA COMPUTACIONAL 64

8.18 Geometria Analítica


Pontos de intersecção de dois círculos: p
d= (x1 − x2 )2 + (y1 − y2 )2 (8.53)
r12 − r22 + d2
l= (8.54)
2d
q
h = r12 − l2 (8.55)
l h
x= (x2 − x1 ) ± (y2 − y1 ) + x1 (8.56)
d d
l h
y = (y2 − y1 ) ∓ (x2 − x1 ) + y1 (8.57)
d d

8.19 Ponto ótimo numa linha


Dado um conjunto de pontos x[i], 0 ≤ i < N , o ponto x que minimiza
−1
NP
|x − x[i]|
i=0

é o ponto médio do vetor ordenado (mediana): x[N/2], se N é ímpar ou qualquer ponto em [x[N/2 − 1], x[N/2]], se N é par.
Capítulo 9

Miscelânea

9.1 Algoritmo de Mo

Resolve queries offline em O((N + Q) N ). É necessário que o update de queries seja O(1).
Pra usar como árvore chamar treemo(root). arr[i] guarda a propriedade dos nós em pre-pos ordem, inv[i] guarda de qual
nó veio arr[i]. Para usar com as arestas colocar a propriedade em c[u] a propriedade de e(u, parent[u]).
CUIDADO: no modo árvore ele muda o valor de N .

#include <cmath> int l = 1 , r = 0 ;


#include <c s t r i n g > curAns = 0 ;
#include <i o s t r e a m > f o r ( i n t i =0; i <Q; i ++){
#include <a l g o r i t h m > query & q = q r s [ i ] ;
using namespace s t d ; while ( r > q . r ) c h e c k ( r −−) ;
#define MAXN 200009 while ( r < q . r ) c h e c k(++r ) ;
while ( l < q . l ) c h e c k ( l ++) ;
i n t a r r [MAXN] , N, sn , Q; while ( l > q . l ) c h e c k(−− l ) ;
bool a p p e a r e d [MAXN] ; check ( q . l c a ) ;
i n t i n v [MAXN] ; //mo t r e e q . ans = curAns ;
check ( q . l c a ) ;
struct query { }
i n t l , r , id , l c a ; s o r t ( q r s , q r s+Q, &idcomp ) ;
l l ans ; }
query ( ) { l=r=i d=l c a =−1; }
query ( i n t _id , i n t _l , i n t _r ) { /∗ Codigo pra LCA a q u i ∗/
i d = _id ; l = _l ; r = _r ; l c a = −1;
} //Mo para a r v o r e s
} q r s [MAXN] ; i n t s t [MAXN] , en [MAXN] , cnt , c [MAXN] ;
bool lrcomp ( query a , query b ) { void p r e p o s ( i n t u , i n t p ) {
i f ( a . l / sn != b . l / sn ) return a . l / sn < b . l / sn ; a r r [ c n t ] = c [ u ] ; i n v [ c n t ] = u ; s t [ u ] = c n t ++;
return a . r > b . r ; f o r ( i n t i =0; i <( i n t ) a d j L i s t [ u ] . s i z e ( ) ; i ++) {
} int v = a d j L i s t [ u ] [ i ] . f i r s t ;
bool idcomp ( query a , query b ) { i f ( v != p ) p r e p o s ( v , u ) ;
return a . i d < b . i d ; }
} a r r [ c n t ] = c [ u ] ; i n v [ c n t ] = u ; en [ u ] = c n t ++;
l l f r e q [MAXN] , curAns ; }
void c h e c k ( i n t i ) { void treemo ( i n t r o o t ) {
i f ( i < 0 | | i >= N) return ; cnt = 0 ;
// i f ( a p p e a r e d [ i ] ) { //mo a r r a y p r e p o s ( r o o t , −1) ; computeP ( r o o t ) ;
i f ( a p p e a r e d [ i n v [ i ] ] ) { //mo t r e e N = cnt ;
f r e q [ a r r [ i ]] − −; f o r ( i n t i =0 , u , v , l c a ; i <Q; i ++) {
i f ( f r e q [ a r r [ i ] ] == 0 ) curAns −−; query & q = q r s [ i ] ;
} u = q . l ; v = q . r ; l c a = LCA( u , v ) ;
else { i f ( s t [ u ] > s t [ v ] ) swap ( u , v ) ;
i f ( f r e q [ a r r [ i ] ] == 0 ) curAns++; // i f ( l c a == u ) q . l = s t [ u ]+1 , q . l c a = −1;
f r e q [ arr [ i ]]++; // p r o p r i e d a d e na a r e s t a
} // e l s e q . l = en [ u ] , q . l c a = −1;
appeared [ inv [ i ] ] = ! appeared [ inv [ i ] ] ; //mo t r e e i f ( l c a == u ) q . l = s t [ u ] , q . l c a = −1; //
// a p p e a r e d [ i ] = ! a p p e a r e d [ i ] ; //mo a r r a y p r o p r i e d a d e no noh
} e l s e q . l = en [ u ] , q . l c a = s t [ l c a ] ;
void mo ( ) { q . r = st [ v ] ;
sn = s q r t (N) ; }
s o r t ( q r s , q r s+Q, &lrcomp ) ; mo ( ) ;
memset(& f r e q , 0 , s i z e o f f r e q ) ; }
memset(& appeared , f a l s e , s i z e o f a p p e a r e d ) ;

65
CAPÍTULO 9. MISCELÂNEA 66

9.2 Algoritmo de Mo sem remoção



Algoritmo de Mo O((N +Q) N ) para responder queries sem suporte da operação de remoção (Ex: Union-find). Preencher as
funções: add(i), adiciona o elemento i à estrutura; save() cria um ponto de retorno no tempo da estrutura; reset(), retorna
ao último ponto salvo; clear(), limpa a estrutura. Atualizar e limpar curAns.

#include <a l g o r i t h m > save ( ) ;


#include <v e c t o r > solvequeries ( l , r , bl ) ;
using namespace s t d ; reset () ;
#define MAXN 100009 }
#define MAXS 320 }

typedef p a i r <int , int> i i ; void b l o c k q u e r y ( i n t l , i n t r , i n t i d ) {


i n t a r r [MAXN] , N, sn , ans [ i ] , curAns ; clear () ;
v e c t o r <i i > q u e r i e s [MAXN] [ MAXS ] ; f o r ( i n t i=l ; i <=r ; i ++) add ( i ) ;
ans [ i d ] = curAns ;
void add ( i n t i ) { ... } }
void save ( ) { . . . }
void reset () { . . . } void mo ( ) {
void clear () { . . . } sn = s q r t (N) ;
f o r ( i n t q=1 , u , v ; q<=Q; q++) {
void s o l v e q u e r i e s ( i n t l , i n t r , i n t b l ) { s c a n f ( "%d␣%d" , &u , &v ) ;
f o r ( i n t k =0; k<( i n t ) q u e r i e s [ l ] [ b l ] . s i z e ( ) ; k++) { i f ( u/ sn == v/ sn ) b l o c k q u e r y ( u , v , q ) ;
i i cur = q u e r i e s [ l ] [ bl ] [ k ] ; e l s e q u e r i e s [ u ] [ v/ sn ] . push_back ( i i ( v , q ) ) ;
while ( r < c u r . f i r s t ) add(++r ) ; }
ans [ c u r . s e c o n d ] = curAns ; f o r ( i n t i =1; i <=N; i ++) {
} f o r ( i n t j =0; j <MAXS; j ++) {
} s o r t ( q u e r i e s [ i ] [ j ] . begin () ,
q u e r i e s [ i ] [ j ] . end ( ) ) ;
void s o l v e b l o c k ( i n t b l ) { }
clear () ; }
i n t r = min ( b l ∗ sn , N) ; f o r ( i n t j =1; j <MAXS; j ++) s o l v e b l o c k ( j ) ;
f o r ( i n t l=r ; l > 0 ; l −−) { }
add ( l ) ;

9.3 Iteração sobre polyominos


Itera sobre todas as possíveis figuras de polyominos em uma grade. Posições com used 1 são proibidas. Colocar borda com
1’s. Neste algoritmo em específico, calcula a soma máxima. used = 2 representa as posições usadas e path guarda tais
posições.

#include <i o s t r e a m > used [ c o o r d [ n ] . f i r s t ] [ c o o r d [ n ] . s e c o n d ] = 1 ;


#include <a l g o r i t h m > return ;
#include <v e c t o r > }
#include <c s t r i n g > v e c t o r <i i > n e i = n e i g h t b o r s ( c o o r d [ n ] ) ;
#define MAXN 500 i i next ;
using namespace s t d ; i n t nadded = 0 ;
f o r ( i n t i =0; i <4; i ++){
typedef p a i r <int , int> i i ; next = n e i [ i ] ;
i i c o o r d [MAXN] , path [MAXN] ; i f ( ! used [ n e x t . f i r s t ] [ n e x t . s e c o n d ] ) {
i n t used [MAXN] [MAXN] ; used [ n e x t . f i r s t ] [ n e x t . s e c o n d ] = 1 ;
i n t mat [MAXN] [MAXN] , maxsum , N, M, nused ; c o o r d [ nused ] = n e x t ;
nadded++; nused++;
v e c t o r <i i > n e i g h t b o r s ( i i pos ) { }
v e c t o r <i i > v ; }
v . push_back ( i i ( pos . f i r s t +1 , pos . s e c o n d ) ) ; f o r ( i n t i = n+1 , nextsum ; i <nused ; i ++){
v . push_back ( i i ( pos . f i r s t −1 , pos . s e c o n d ) ) ; nextsum = mat [ c o o r d [ i ] . f i r s t ] [ c o o r d [ i ] . s e c o n d
v . push_back ( i i ( pos . f i r s t , pos . s e c o n d +1) ) ; ];
v . push_back ( i i ( pos . f i r s t , pos . second −1) ) ; d f s ( sum + nextsum , h+1 , i ) ;
return v ; }
} while ( nadded−−>0){
nused −−;
//0−>unused , 1−>t o be used , 2−>used n e x t = c o o r d [ nused ] ;
void d f s ( i n t sum , i n t h , i n t n ) { used [ n e x t . f i r s t ] [ n e x t . s e c o n d ] = 0 ;
used [ c o o r d [ n ] . f i r s t ] [ c o o r d [ n ] . s e c o n d ] = 2 ; }
path [ h ] = c o o r d [ n ] ; used [ c o o r d [ n ] . f i r s t ] [ c o o r d [ n ] . s e c o n d ] = 1 ;
i f ( h == M) { }
maxsum = max( maxsum , sum ) ;
CAPÍTULO 9. MISCELÂNEA 67

9.4 Quadrádo Mágico Ímpar


Gera uma matriz quadrática n × n em O(n2 ), n ímpar, tal que a soma dos elementos ao longo de todas as linhas, de todas
as colunas e das duas diagonais é a mesma. Os elementos vão de 1 a n2 . A matriz é indexada em 0.

#include <c s t r i n g > i f ( mat [ ( i +1)%n ] [ ( j +1)%n ] > 0 ) {


#define MAXN 1009 i = ( i −1+n )%n ;
}
i n t mat [MAXN] [MAXN] , n ; //0−i n d e x e d else {
i = ( i +1)%n ;
void m a g i c s q u a r e ( ) { j = ( j +1)%n ;
i n t i=n−1 , j=n / 2 ; }
memset(&mat , 0 , s i z e o f mat ) ; }
f o r ( i n t k =1; k<=n∗n ; k++){ }
mat [ i ] [ j ] = k ;

9.5 Expressão Parentética para Polonesa


Dada uma expressão matemática na forma parentética, converte para a forma polonesa e retorna o tamanho da string na
forma polonesa. Ex.: (2 ∗ 4/a ∧ b)/(2 ∗ c) → 24 ∗ ab ∧ /2c ∗ /.

#include <map> p o l i s h [ l e n ++] = op . top ( ) ;


#include <s t a c k > op . pop ( ) ;
using namespace s t d ; }
op . push ( paren [ i ] ) ;
i n l i n e bool isOp ( char c ) { }
return c== ’+ ’ | | c== ’− ’ | | c== ’ ∗ ’ | | c== ’ / ’ | | c e l s e i f ( paren [ i ]== ’ ( ’ )
== ’ ^ ’ ; op . push ( ’ ( ’ ) ;
} e l s e i f ( paren [ i ]== ’ ) ’ ) {
while ( op . top ( ) != ’ ( ’ ) {
i n l i n e bool i s C a r a c ( char c ) { p o l i s h [ l e n ++] = op . top ( ) ;
return ( c>= ’ a ’ && c<= ’ z ’ ) | | ( c>= ’A ’ && c<= ’ Z ’ ) op . pop ( ) ;
| | ( c>= ’ 0 ’ && c<= ’ 9 ’ ) ; }
} op . pop ( ) ;
}
i n t p a r e n 2 p o l i s h ( char∗ paren , char∗ p o l i s h ) { e l s e i f ( i s C a r a c ( paren [ i ] ) )
map<char , int> p r e c ; p o l i s h [ l e n ++] = paren [ i ] ;
prec [ ’ ( ’ ] = 0; }
p r e c [ ’+ ’ ] = p r e c [ ’− ’ ] = 1 ; while ( ! op . empty ( ) ) {
prec [ ’ ∗ ’ ] = prec [ ’ / ’ ] = 2; p o l i s h [ l e n ++] = op . top ( ) ;
prec [ ’^ ’ ] = 3 ; op . pop ( ) ;
int l e n = 0 ; }
s t a c k <char> op ; polish [ len ] = 0;
f o r ( i n t i =0; paren [ i ] > 0 ; i ++){ return l e n ;
i f ( isOp ( paren [ i ] ) ) { }
while ( ! op . empty ( ) && p r e c [ op . top ( ) ]>=
p r e c [ paren [ i ] ] ) {

9.6 Problema do histograma


Algoritmo O(n) para resolver o problema do retângulo máximo em um histograma.

#include <s t a c k > i f ( i < n && ( s . empty ( ) | | v e t [ s . top ( ) ] <= v e t


#define MAXN 100009 [ i ] ) ) s . push ( i ++) ;
#define INF ( 1LL<<60) else {
using namespace s t d ; tp = s . top ( ) ;
s . pop ( ) ;
typedef long long l l ; c u r = v e t [ tp ] ∗ ( s . empty ( ) ? i : i − s . top
( ) − 1) ;
l l h i s t o g r a m ( l l ∗ vet , i n t n ) { i f ( ans < c u r ) ans = c u r ;
s t a c k <l l > s ; }
l l ans = 0 , tp , c u r ; }
int i = 0 ; return ans ;
while ( i < n | | ! s . empty ( ) ) { }
CAPÍTULO 9. MISCELÂNEA 68

9.7 Problema do casamento estável


Resolve o problema do casamento estável em O(n2 ). m é o número de homens, n é o número de mulheres, L[i] é a lista de
preferências do i-ésimo homem (melhor primeiro), R[i][j] é a nota que a mulher i dá ao homem j. R2L[i] == j retorna se a
mulher i está casada com o homem j, L2R[i] == j retorna se o homem i está casado com a mulher j.

#include <c s t r i n g > while ( true ) {


#define MAXN 1009 wom = L [ man ] [ p [ man] + + ] ;
i f ( R2L [ wom ] < 0 | | R[ wom ] [ man ] > R[
i n t m, n , p [MAXN] ; wom ] [ R2L [ wom ] ] ) break ;
i n t L [MAXN] [MAXN] , R[MAXN] [MAXN] ; }
i n t R2L [MAXN] , L2R [MAXN] ; hubby = R2L [ wom ] ;
R2L [ L2R [ man ] = wom ] = man ;
void s t a b l e M a r r i a g e ( ) { man = hubby ;
memset (R2L , −1, s i z e o f (R2L) ) ; }
memset ( p , 0 , s i z e o f ( p ) ) ; }
f o r ( i n t i = 0 , wom, hubby ; i < m; i ++){ }
f o r ( i n t man = i ; man >= 0 ; ) {

9.8 Teoremas e Fórmulas


• Fórmula de Cayley: existem nn−2 árvores geradoras em um grafo completo de n vértices.

• Desarranjo: o número der(n) de permutações de n elementos em que nenhum dos elementos fica na posição original é
dado por: der(n) = (n − 1)(der(n − 1) + der(n − 2)), onde der(0) = 1 e der(1) = 0.
• Teorema de Erdos
Pn Gallai: é P Pkque uma array represente os graus dos vértices de um nó: d1 ≥
condição suficiente para
k
d2 ≥ ... ≥ dn , i=1 di = 2k, i=1 di ≤ k(k − 1) + i=k+1 min(di , k).

• Fórmula de Euler para grafos planares: V − E + F = 2, onde F é o número de faces.


• Círculo de Moser: o número de peças em que um círculo pode ser divido por cordas ligadas a n pontos tais que não se
tem 3 cordas internamente concorrentes é dada por: g(n) = C4n + C2n + 1.
• Teorema de Pick: se I é o número de pontos inteiros dentro de um polígono, A a área do polígono e b o número de
pontos inteiros na borda, então A = i + b/2 − 1 .

• O número de árvores geradores em um grafo bipartido completo é mn−1 × nm−1 .


• Teorema de Kirchhoff: o número de árvores geradoras em um grafo é igual ao cofator da sua matriz laplaciana L.
L = D − A, em que D é uma matriz diagonal em que aii = di e A é a matriz de adjacência.
• Teorema de Konig: a cobertura mínima de vértices em um grafo bipartido (o número mínimo de vértices a serem
removidos para se remover todas as arestas) é igual ao pareamento máximo do grafo.
• Teorema de Zeckendorf: qualquer inteiro positivo pode ser representado pela soma de números de Fibonacci que não
inclua dois números consecutivos. Para achar essa soma, usar o algoritmo guloso, sempre procurando o maior número
de fibonacci menor que o número.

• Teorema de Dilworth: em um DAG que representa um conjunto parcialmente ordenado, uma cadeia é um subconjunto
de vértices tais que todos os pares dentro dele são comparáveis; uma anti-cadeia é um subconjunto tal que todos os pares
de vértices dele são não comparáveis. O teorema afirma que a partição mínima em cadeias é igual ao comprimenton da
maior anti-cadeia. Para computar, criar um grafo bipartido: para cada vértice x, duplicar para ux e vx . Uma aresta
x → y é escrita como ux → vy . O tamanho da partição mínima, também chamada de largura do conjunto, é N − o
emparelhamento máximo.

• Teorema de Mirsky: semelhante ao teorema de Dilworth, o tamanho da partição mínima em anti-cadeias é igual ao
comprimento da maior cadeia.

Você também pode gostar