diff --git a/.gitignore b/.gitignore
index a91a137cced819927f2c25cf2d63de912b63b289..da699601f6006f002460a5382a193f1c186e1536 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,9 @@ _minted*
 *.dvi
 *.synctex.gz
 *.aux
+
+testes/hld-ps
+testes/fenwick-tree
+testes/fenwick-2d-tree
+testes/lstit
+testes/monotone
diff --git a/Makefile b/Makefile
index 484610ce03e03371c4e960e5910e6dcdebc3b458..9f1f6cfe521701cd72e4e89a93ff510b7207036f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,29 +1,28 @@
 .PHONY: all test
 
-all: testes/hld-ps.cpp testes/fenwick-tree.cpp testes/fenwick-2d-tree.cpp testes/lazy-segment-tree.cpp testes/convex-hull.cpp caderno.pdf
+all: testes/fenwick-tree testes/fenwick-2d-tree testes/hld-ps testes/lstit testes/monotone caderno.pdf
 
-caderno.pdf: fontes/*.cpp caderno/caderno.tex
-	latexmk caderno/caderno
+caderno.pdf: fontes/*.cpp fontes/*.h caderno/caderno.tex
+	latexmk caderno/caderno -e '$$pdflatex='lualatex -shell-escape''
 
-test: testes/hld-ps.cpp testes/fenwick-tree.cpp testes/fenwick-2d-tree.cpp testes/lazy-segment-tree.cpp testes/convex-hull.cpp
-	g++ -O2 testes/hld-ps.cpp && ./a.out <testes/hld-ps.in | diff - testes/hld-ps.out
-	g++ -O2 testes/fenwick-tree.cpp && ./a.out
-	g++ -O2 testes/fenwick-2d-tree.cpp && ./a.out
-	g++ -O2 testes/lazy-segment-tree.cpp && ./a.out
-	g++ -O2 testes/convex-hull.cpp && ./a.out
-	rm a.out
+test: testes/fenwick-tree testes/fenwick-2d-tree testes/hld-ps testes/lstit testes/monotone
+	./testes/hld-ps <testes/hld-ps.in | colordiff -u - testes/hld-ps.out
+	./testes/fenwick-tree
+	./testes/fenwick-2d-tree
+	./testes/lstit
+	./testes/monotone
 
-testes/fenwick-tree.cpp: fontes/template.cpp testes/fenwick-tree.gen fontes/fenwick-tree.cpp
-	testes/fenwick-tree.gen
+testes/fenwick-tree: testes/fenwick-tree.cpp fontes/fenwick-tree.h
+	g++ -O2 testes/fenwick-tree.cpp -o testes/fenwick-tree
 
-testes/fenwick-2d-tree.cpp: fontes/template.cpp testes/fenwick-2d-tree.gen fontes/fenwick-2d-tree.cpp
-	testes/fenwick-2d-tree.gen
+testes/fenwick-2d-tree: testes/fenwick-2d-tree.cpp fontes/fenwick-2d-tree.h
+	g++ -O2 testes/fenwick-2d-tree.cpp -o testes/fenwick-2d-tree
 
-testes/hld-ps.cpp: fontes/template.cpp testes/hld-ps.gen fontes/heavy-light-decomposition.cpp fontes/prefix-sum.cpp
-	testes/hld-ps.gen
+testes/hld-ps: testes/hld-ps.cpp fontes/hld.h
+	g++ -O2 testes/hld-ps.cpp -o testes/hld-ps
 
-testes/lazy-segment-tree.cpp: fontes/template.cpp testes/lazy-segment-tree.gen fontes/lazy-segment-tree.cpp
-	testes/lazy-segment-tree.gen
+testes/lstit: fontes/template.cpp testes/lstit.cpp
+	g++ -O2 testes/lstit.cpp -o testes/lstit
 
-testes/convex-hull.cpp: fontes/template.cpp testes/convex-hull.gen fontes/convex-hull.cpp
-	testes/convex-hull.gen
+testes/monotone: fontes/template.cpp testes/monotone.cpp
+	g++ -O2 testes/monotone.cpp -o testes/monotone
diff --git a/caderno.pdf b/caderno.pdf
index 67cd33ccb05495ab52f90b2d585ba956b99027ce..ec8f0d360fd18a194fae9d1448a4269a19a65092 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/caderno/caderno.tex b/caderno/caderno.tex
index 51cde7895198889800e88a1a5c8e189407c8d0e9..116c6e61665146a51579362b37759e57decdc148 100644
--- a/caderno/caderno.tex
+++ b/caderno/caderno.tex
@@ -1,6 +1,5 @@
-\documentclass[titlepage]{article}
-\usepackage[margin=1cm,footskip=.5cm]{geometry}
-\usepackage[utf8]{inputenc}
+\documentclass[titlepage,a4paper]{article}
+\usepackage[margin=1cm,bmargin=2cm,footskip=1cm]{geometry}
 \usepackage{minted}
 \usepackage[T1]{fontenc}
 \usemintedstyle{vs}
@@ -8,41 +7,53 @@
 \usepackage[brazilian]{babel}
 \usepackage{lmodern}
 \usepackage{amsmath}
-\inputencoding{utf8}
+\usepackage{caption}
+\usepackage{multirow}
+\usepackage{fontspec}
+\usepackage{hyperref}
+\setmonofont{Fantasque Sans Mono}
 
 \newcommand{\bigO}{\mathcal{O}}
-\newcommand{\importsource}[2][cpp]{\inputminted[linenos]{#1}{fontes/#2}}
+\newcommand{\importsource}[2][cpp]{
+  \footnotesize
+  \inputminted[linenos, xleftmargin=\parindent]{#1}{fontes/#2}
+}
 
 \begin{document}
+\twocolumn
 
-\title{Caderno de Maratona}
+\title{Caderno de Maratona de Programação}
 \author{Fernando Kiotheka$^1$}
-\date{%
-  $^1$Universidade Federal do Paraná\\[2ex]
-  \today
-}
+\date{$^1$Universidade Federal do Paraná\\[2ex]\today}
 
 \maketitle
-%\tableofcontents
-\newpage
-
-\section{C++}
-
-\begin{multicols}{2}
-\subsection{Esboços}
-\importsource{template.cpp}
-.bashrc
-\importsource[bash]{bashrc}
-.vimrc
-\importsource[vim]{vimrc}
-stress.sh
-\importsource[bash]{stress.sh}
-gen.cpp
-\importsource{gen.cpp}
-\end{multicols}
+\tableofcontents
+\begin{table*}
+\centering
+  \begin{tabular}{lll}
+    \hline
+    $n$ & Pior algoritmo que passa & Comentário \\ \hline
+    $\leq [10..11]$ & $\bigO(n!)$, $\bigO(n^6)$ & ex. Enumerar permutações \\
+    $\leq [15..18]$ & $\bigO(2^n n^2)$ & ex. PD do Caixeiro-Viajante \\
+    $\leq [18..22]$ & $\bigO(2^n n)$ & ex. PD com técnica de máscara de bits \\
+    $\leq 100$ & $\bigO(n^4)$ & ex. PD com 3 dimensões + laço $\bigO(n)$, $_{n}C_{k=4}$ \\
+    $\leq 400$ & $\bigO(n^3)$ & ex. Floyd-Warshall \\
+    $\leq 2\cdot 10^3$ & $\bigO(n^2 \lg n)$ & ex. 2 laços aninhados + consulta em árvore \\
+    $\leq 5\cdot 10^4$ & $\bigO(n^2)$ & ex. Bubble/Selection/Insertion Sort \\
+    $\leq 10^5$ & $\bigO(n \lg^2 n) = \bigO((\lg n)(\lg n))$ & ex. Construção de vetor de sufixos padrão \\
+    $\leq 10^6$ & $\bigO(n \lg n)$ & ex. Merge Sort, construir árvore de segmento \\
+    $\leq 10^7$ & $\bigO(n \lg \lg n)$ & ex. Crivo de Eratóstenes, função totiente \\
+    $\leq 10^8$ & $\bigO(n)$, $\bigO(\lg n)$, $\bigO(1)$ & ex. Solução matemática. Maioria dos problemas tem $n \leq 10^9$ (gargalo de E/S) \\
+    \hline
+  \end{tabular}
+  \caption*{$10^8$ operações por segundo.}
+\end{table*}
 
-\subsection{Comparações}
-\begin{multicols}{2}
+\newpage
+\section{Teoria}
+\subsection{Comparações algorítmicas}
+\begin{table}[ht]
+  \centering
   \begin{tabular}{l|r}
     \hline
     $\lg 10$ (\texttt{1E1}) & 2.3 \\
@@ -58,9 +69,14 @@ gen.cpp
     $\lg 100000000000$ (\texttt{1E10}) & 25.3 \\
     $\lg 1000000000000$ (\texttt{1E11}) & 27.6 \\
     $\lg 10000000000000$ (\texttt{1E12}) & 29.9 \\
+    $2^{10}$ & $\approx 10^{3}$ \\
+    $2^{20}$ & $\approx 10^{6}$ \\
     \hline
   \end{tabular}
+\end{table}
 
+\begin{table}[ht]
+  \centering
   \begin{tabular}{crcccc}
     \hline
     Sinal & Tipo & Bits & Máximo & Dígitos \\
@@ -77,43 +93,11 @@ gen.cpp
      $+$  & \texttt{\_\_int128} & 128 & $\approx 3 \cdot 10^{38}$ & 38 \\
     \hline
   \end{tabular}
+\end{table}
 
-  \begin{tabular}{r|l}
-    \hline
-    Valor & Estimativa \\
-    \hline
-    $2^{10}$ & $10^{3}$ \\
-    $2^{20}$ & $10^{6}$ \\
-    \hline
-  \end{tabular}
-\end{multicols}
-
-Estimativa computacional: $10^8$ operações por segundo.
-
-\begin{center}
-  \begin{tabular}{lll}
-    \hline
-    $n$ & Pior algoritmo que passa & Comentário \\ \hline
-    $\leq [10..11]$ & $\bigO(n!)$, $\bigO(n^6)$ & ex. Enumerar permutações \\
-    $\leq [15..18]$ & $\bigO(2^n n^2)$ & ex. PD do Caixeiro-Viajante \\
-    $\leq [18..22]$ & $\bigO(2^n n)$ & ex. PD com técnica de máscara de bits \\
-    $\leq 100$ & $\bigO(n^4)$ & ex. PD com 3 dimensões + laço $\bigO(n)$, $_{n}C_{k=4}$ \\
-    $\leq 400$ & $\bigO(n^3)$ & ex. Floyd-Warshall \\
-    $\leq 2\cdot 10^3$ & $\bigO(n^2 \lg n)$ & ex. 2 laços aninhados + consulta em árvore \\
-    $\leq 5\cdot 10^4$ & $\bigO(n^2)$ & ex. Bubble/Selection/Insertion Sort \\
-    $\leq 10^5$ & $\bigO(n \lg^2 n) = \bigO((\lg n)(\lg n))$ & ex. Construção de vetor de sufixos padrão \\
-    $\leq 10^6$ & $\bigO(n \lg n)$ & ex. Merge Sort, construir árvore de segmento \\
-    $\leq 10^7$ & $\bigO(n \lg \lg n)$ & ex. Crivo de Eratóstenes, função totiente \\
-    $\leq 10^8$ & $\bigO(n)$, $\bigO(\lg n)$, $\bigO(1)$ & ex. Solução matemática. Maioria dos problemas tem $n \leq 10^9$ (gargalo de E/S) \\
-    \hline
-  \end{tabular}
-\end{center}
-
-\newpage
-\section{Matemática}
-\begin{multicols}{2}
+\subsection{Progressões}
 \begin{align*}
-  a_n = a_k + r(n - k)
+  a_n = a_k + r(n - k) \\
   a_n = a_k q^{(n-k)}
 \end{align*}
 \begin{itemize}
@@ -125,149 +109,469 @@ Estimativa computacional: $10^8$ operações por segundo.
   S_n = \frac{n(a_1 + a_n)}{2} \\
   S_n = \frac{a_1(q^n - 1)}{q-1}
 \end{align*}
+
+\subsection{Identidades binomiais}
 \begin{align*}
   \binom{n}{k} &= \binom{n-1}{k-1} + \binom{n-1}{k}, \forall n \ge 0 \wedge 0 \le k \le n \\
   \binom{n}{k} &= \frac{n!}{k!(n-k)!}
 \end{align*}
-\end{multicols}
 
-\section{Algoritmos}
-\begin{multicols}{2}
-  \importsource{merge-sort.cpp}
-\end{multicols}
+\subsection{Teorema de Lucas}
+\begin{align*}
+  \binom{n}{m} = \Pi_{i=0}^{k} \binom{n_i}{m_i} \pmod{p}
+\end{align*}
+Para $p$ primo, $n_i$ e $m_i$ são coeficientes das representações de $n$ e $m$ na base $p$.
 
-\section{Estrutura de Dados}
+\subsection{Teoremas de Fermat}
+\begin{align*}
+  a^p = a \pmod{p} \\
+  a^{p-1} = 1 \pmod{p} \\
+  (a + b)^p = a^p + b^p \pmod{p} \\
+  a^{-1} = a^{p-2} \pmod{p}
+\end{align*}
+onde $p$ é primo.
 
-\subsection{Pilha/Fila mínima}
-\begin{multicols}{2}
-  \importsource{min-stack.cpp}
-  \importsource{min-queue.cpp}
-  \importsource{min-queue-2.cpp}
-  \importsource{min-queue-3.cpp}
-  \importsource{custom-hash.cpp}
-\end{multicols}
-
-\subsection{LIS}
-\begin{multicols}{2}
-\importsource{lis.cpp}
-\importsource{lisnlgn.cpp}
-\end{multicols}
+\subsection{Módulo no expoente}
+\begin{align*}
+  a^n = a^{n \pmod{\phi(m)}} \pmod{m}
+\end{align*}
+para $a$ e $m$ coprimos.
 
-\subsection{DP on broken profile}
+\subsection{Números de Catalão}
+{\sloppy
+1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,
+9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420,
+24466267020, 91482563640, \\343059613650, 1289904147324, 4861946401452,
+\\18367353072152, 69533550916004, 263747951750360, \\1002242216651368.}
+
+\begin{align*}
+  C_n = \frac{1}{n+1} \binom{2n}{n} = \frac{(2n)!}{(n+1)!n!} = \Pi^n_{k=2} \frac{n+k}{k}, n \ge 0.
+\end{align*}
+
+\section{C++}
+
+\subsection{Esboço}
+\importsource{template.cpp}
+\subsection{Bashrc}
+\importsource[bash]{bashrc}
+\subsection{Vimrc}
+\importsource[vim]{vimrc}
+\subsection{Teste de estresse}
+\importsource[bash]{stress.sh}
+\subsection{Gerador}
+\importsource{gen.cpp}
+
+\section{Estrutura de Dados}
+\subsection{Soma de prefixos}
+\importsource{prefix-sum.h}
 
 \subsection{Árvore de Fenwick}
-\begin{multicols}{2}
-\importsource{fenwick-tree.cpp}
-\end{multicols}
+\begin{tabular}{l|l|l}
+  \hline
+  1-indexada &
+  Atualização $\bigO(\lg n)$ &
+  Consulta $\bigO(\lg n)$ \\
+  \hline
+\end{tabular}
+
+\vspace{4pt}
+\noindent
+\begin{tabular}{lll}
+  \hline
+  \textbf{Atualização} & \textbf{Consulta} & \textbf{Funções} \\ \hline
+  Ponto & Intervalo & \texttt{add} + \texttt{sum\_inclusive} \\
+  Intervalo & Ponto & \texttt{add\_inclusive} + \texttt{pref} \\
+  \hline
+\end{tabular}
+
+\importsource{fenwick-tree.h}
 
 \subsection{Árvore de Fenwick 2D}
-\begin{multicols}{2}
-\importsource{fenwick-2d-tree.cpp}
-\end{multicols}
+\begin{tabular}{l|l|l}
+  \hline
+  1-indexada &
+  Atualização $\bigO(\lg^2 n)$ &
+  Consulta $\bigO(\lg^2 n)$ \\
+  \hline
+\end{tabular}
+
+\importsource{fenwick-2d-tree.h}
+
+\subsection{Árvore de Fenwick intervalar}
+\begin{tabular}{l|l|l}
+  \hline
+  1-indexada &
+  Atualização $\bigO(\lg n)$ &
+  Consulta $\bigO(\lg n)$ \\
+  \hline
+\end{tabular}
+
+\importsource{fenwick-range-tree.h}
+
+\subsection{União-busca}
+\importsource{disjoint.h}
+
+\subsection{Pilha mínima}
+\importsource{min-stack.h}
+
+\subsection{Fila mínima (sabendo o que remover)}
+\importsource{min-queue.h}
+
+\subsection{Fila mínima}
+\importsource{min-queue-2.h}
+
+\subsection{Fila mínima (guarda os elementos)}
+\importsource{min-queue-3.h}
+
+\subsection{Maior elemento anterior}
+\importsource{pge.h}
+
+\subsection{Menor elemento anterior}
+\importsource{ple.h}
+
+\subsection{Próximo maior elemento}
+\importsource{nge.h}
+
+\subsection{Próximo menor elemento}
+\importsource{nle.h}
+
+\subsection{Hash map simples}
+\importsource{simple-hash.h}
+
+\subsection{Hash customizado}
+\importsource{custom-hash.h}
+
+\subsection{Conjunto de intervalos coloridos}
+\importsource{interval-set.h}
+
+\subsection{Árvore de segmentos recursiva}
+\begin{tabular}{l|l|l}
+  \hline
+  \multicolumn{3}{l}{1-indexada} \\ \hline
+  Construção $\bigO(n)$ &
+  Atualização $\bigO(\lg n)$ &
+  Consulta $\bigO(\lg n)$ \\
+  \hline
+\end{tabular}
 
-\subsection{Árvore de Segmentos Preguiçosa}
-\begin{center}
-\begin{tabular}{c|c|c|c}
+\vspace{4pt}
+\noindent
+\begin{tabular}{cccc}
   \hline
-  Macro & RSQ & RMQ & RMaxQ \\ \hline
-  \texttt{LST\_OP(X, Y)} & \texttt{(X + Y)} & \texttt{min(X, Y)} & \texttt{max(X, Y)} \\
-  \texttt{LST\_NEUTRAL} & 0 & \texttt{numeric\_limits<int>::max()} & \texttt{numeric\_limits<int>::min()} \\
-  \texttt{LST\_FACTOR} & \texttt{(tb - ta + 1)} & \texttt{1} & \texttt{1} \\
+  Macro & + & mín & máx \\ \hline
+  \texttt{OP(X, Y)} & \texttt{((X) + (Y))} & \texttt{min(X, Y)} & \texttt{max(X, Y)} \\
+  \texttt{NEUTRAL} & 0 & \texttt{oo} & \texttt{-oo} \\
+  \texttt{FACTOR} & \texttt{(tb - ta + 1)} & \texttt{1} & \texttt{1} \\
   \hline
 \end{tabular}
-\end{center}
-\begin{multicols}{2}
-\importsource{lazy-segment-tree.cpp}
-\end{multicols}
+
+\importsource{strec.h}
+
+\subsection{Árvore de segmentos iterativa}
+\importsource{stit.h}
+
+\subsection{Árvore de segmentos preguiçosa rec.}
+\importsource{lstrec.h}
+
+\subsection{Árvore de segmentos preguiçosa iter.}
+\importsource{lstit.h}
+
+\subsection{Nó de árvore de segmentos}
+\importsource{node.h}
 
 \section{Grafos}
 
-\subsection{Busca}
-\subsubsection{Busca em Profundidade -- DFS (Depth First Search)}
-\importsource{dfs.cpp}
+\subsection{Articulações e Pontes}
+\importsource{articbridges.h}
+
+\subsection{Stoer-Wagner}
+\importsource{stoer-wagner.h}
+
+\subsection{SPFA*}
+
+\subsection{BFS 0-1}
+\importsource{bfs01.h}
 
-\subsubsection{Conectado}
+\subsection{Emparelhamento estável}
+\begin{tabular}{l}
+  \hline
+  $\bigO(n^2)$ \\
+  \hline
+\end{tabular}
+\importsource{stable-matching.h}
+
+\subsection{Fluxo máximo*}
+
+\subsection{Fluxo de custo mínimo*}
+
+\subsection{Busca em profundidade recursiva}
+\importsource{dfsrec.h}
+
+\subsection{Busca em profundidade com pilha}
+\importsource{dfsstack.h}
+
+\subsection{Busca em largura}
+\importsource{bfs.h}
+
+\subsection{Conectado*}
 \importsource{connected.cpp}
 
-\subsubsection{Componentes Fortemente Conectados -- Tarjan}
+\subsection{Componentes fortes -- Tarjan*}
 \importsource{tarjan.cpp}
 
-\subsubsection{Componentes Fortemente Conectados -- Kosaraju}
+\subsection{Componentes fortes -- Kosaraju*}
 \importsource{kosaraju.cpp}
 
-\subsection{Caminhos}
-\subsubsection{Caminho Mínimo com Pesos Não-Negativos -- Dijkstra}
-\importsource{dijkstra.cpp}
+\subsection{Caminho mínimo -- Dijkstra}
+\importsource{dijkstra.h}
 
-\subsubsection{Caminho Mínimo -- Bellman-Ford}
+\subsection{Caminho mínimo -- Bellman-Ford*}
 \importsource{bellman-ford.cpp}
 
-\subsubsection{Todos os Caminhos Mínimos (Programação Dinâmica) -- Floyd-Warshall}
+\subsection{Caminhos mínimos -- Floyd-Warshall*}
 \importsource{floyd-warshall.cpp}
 
-\subsubsection{Ordenação Topológica -- Topological Sorting}
-\importsource{topological-sort.cpp}
+\subsection{Ordenação Topológica}
+\importsource{topo.h}
 
-\subsection{Árvores, LCA, Decomposições}
+\subsection{Árvore geradora mínima -- Prim}
+\importsource{prim.h}
 
-\subsubsection{Árvore Geradora Mínima -- Prim}
-\importsource{prim.cpp}
+\subsection{Árvore geradora mínima -- Kruskal}
+\importsource{kruskal.h}
 
-\subsubsection{Ascensão Binária -- Binary Lifting}
-\begin{multicols}{2}
+\subsection{Ascensão binária*}
 \importsource{binary-lifting.cpp}
-\end{multicols}
 
-\subsubsection{Decomposição Pesado-Leve -- Heavy-Light Decomposition}
-\begin{multicols}{2}
-\importsource{heavy-light-decomposition.cpp}
-\end{multicols}
+\subsection{Menor anc. comum -- Ancensão binária*}
 
-\subsubsection{Decomposição Raíz Quadrada de Árvore -- Square Root Tree Decomposition}
-\importsource{square-root-tree-decomposition.cpp}
+\subsection{Menor anc. comum -- Dec. pesado-leve*}
 
-\section{Geometria}
-
-\subsection{Fecho Convexo (Corrente Monótona) -- Convex Hull (Monotone Chain)}
-\begin{center}
-\begin{tabular}{c|c|c|c|c}
+\subsection{Decomposição pesado-leve}
+\begin{tabular}{l|l}
+  \hline
+  \multicolumn{2}{l}{
+  Precisa de soma de prefixos/árvore de segmentos preguiçosa
+  } \\ \hline
+  \multicolumn{2}{l}{
+    Se usado com pesos nos vértices, use com $\texttt{edge\_wei} = 0$
+  } \\ \hline
+  Construção $\bigO(|V|\lg|V| + |E|)$ &
+  Atualização/Consulta $\bigO(\lg^2 n)$ \\
   \hline
-   & \textbf{Anti-horário} & Horário & Anti-horário Colinear & Horário Colinear \\ \hline
-   Operação & \texttt{>} & \texttt{<} & \texttt{>=} & \texttt{<=} \\ \hline
 \end{tabular}
-\end{center}
-\begin{multicols}{2}
-\importsource{convex-hull.cpp}
-\end{multicols}
+\importsource{hld.h}
+
+\subsection{Decomposição raiz quadrada de árvore}
+\importsource{stdt.h}
 
-\subsection{Sweep angular}
-\importsource{angular-sweep.cpp}
+\subsection{Menor anc. comum -- Dec. raiz quad.}
+\importsource{stdtlca.h}
+
+\subsection{Empar. máximo bipartido -- Kuhn*}
+
+\subsection{Empar. máximo bipartido -- Hopcroft*}
 
 \section{Matemática}
 
-\subsection{Crivo de Eratóstenes}
+\subsection{Problema de Josephus}
+
+\subsection{Operações comuns}
+\importsource{numbers.h}
+
+\subsection{Primeiros e últimos digitos de $n^k$}
+\importsource{nk-first-last-digits.h}
+
+\subsection{Triângulo de Pascal}
+\importsource{pascal-triangle.h}
+
+\subsection{2-SAT*}
+
+\subsection{Inclusão-Exclusão}
+\importsource{inclusion-exclusion.h}
+
+\subsection{Mínimo excluído com conjunto}
+\importsource{mexset.h}
+
+\subsection{Mínimo excluído}
+\importsource{mex.h}
+
+\subsection{Nímero*}
+
+\subsection{Euclides estendido/inv. multiplicativo}
+\begin{tabular}{l}
+  \hline
+$\bigO(\lg \min(a, b))$ \\
+\hline
+\end{tabular}
+\begin{align*}
+  ax + by &= \gcd(a, b) \\
+  ax &= gcd(a, b) \pmod{b} \\
+  (\gcd(a, b) = 1) &\implies (ax = 1 \pmod{b})
+\end{align*}
+\importsource{extgcd.h}
+
+\subsection{Detecção de ciclo}
+\importsource{floyd.h}
+
+\subsection{Equação diofantina linear}
+\begin{align*}
+ax + by = c
+\end{align*}
+\importsource{diophantine.h}
+
+\subsection{Multiplicação -- Karatsuba*}
+
+\subsection{Números de Catalão}
+\importsource{catalan.h}
+
+\subsection{Fatoração por tentativa}
+\begin{tabular}{l}
+  \hline
+  $\bigO(\sqrt{n})$ \\
+\hline
+\end{tabular}
+\importsource{factorize.h}
+
+\subsection{Crivo de Eratóstenes*}
 \importsource{sieve-of-eratosthenes.cpp}
 
-\subsection{Exponenciação rápida}
-\importsource{fast-pow.cpp}
+\subsection{Exponenciação binária*}
+\importsource{binary-pow.h}
 
-\subsection{Exponenciação de matrizes}
+\subsection{Exponenciação de matrizes*}
 \importsource{matrix-mult.cpp}
 
-\subsection{Algoritmo de euclides estendido}
-\importsource{extended-gcd.cpp}
+\subsection{Miller-Rabin*}
 
-\section{Máscaras de Bit e Operações em Bit}
-\importsource{bit-ops.cpp}
+\subsection{Pollard Rho*}
+
+\subsection{Teorema chinês do resto*}
+
+\subsection{Totiente de Euler*}
+\importsource{euler-totient.h}
+
+\subsection{Fibonacci*}
+
+\subsection{Teorema chinês do resto generalizado*}
 
 \section{Strings}
 
+\subsection{Árvore de sufixos}
+\importsource{suffix-tree.h}
+
+\subsection{Aho-Corasick*}
+\importsource{acs.h}
+
+\subsection{Algoritmo Z*}
+
+\subsection{Autômato de Sufixo*}
+
 \subsection{KMP}
-\importsource{kmp.cpp}
+\begin{tabular}{l|l}
+  \hline
+  Pré-computação $\bigO(m)$ &
+  Busca $\bigO(n + m)$ \\
+  \hline
+\end{tabular}
+\importsource{kmp.h}
+
+\subsection{Autômato KMP*}
+
+\subsection{Rabin-Karp}
+\importsource{rabinkarp.h}
+
+\subsection{Vetor de sufixos*}
+
+\subsection{Vetor de sufixos com ordenação por contagem*}
+
+\subsection{Trie}
+\importsource{trie.h}
+
+\section{Geometria}
+
+\subsection{Pontos}
+\importsource{point.h}
+
+\subsection{Fecho convexo com corrente monotônica}
+\begin{tabular}{l}
+  \hline
+  $\bigO(n \lg n)$ \\
+  \hline
+\end{tabular}
+\importsource{monotone.h}
+
+\subsection{Fecho convexo de Graham}
+\begin{tabular}{l}
+  \hline
+  $\bigO(n \lg n)$ \\
+  \hline
+\end{tabular}
+\importsource{graham.h}
+
+\subsection{Interseção de retângulos*}
+
+\subsection{Polígono é convexo?*}
+
+\subsection{Ponto dentro do polígono?*}
+
+\subsection{Área de polígono*}
 
-\section{Outros}
+\subsection{Área de polígono de pontos inteiros*}
 
-\subsection{Busca binária}
+\subsection{Distância de segmento e segmento*}
+
+\subsection{Distância de ponto e segmento*}
+
+\subsection{Intersecção de segmento*}
+
+\subsection{Árvore KD}
+\importsource{kd-tree.h}
+
+\subsection{Varredura linear*}
+
+\subsection{Varredura angular}
+\importsource{angular-sweep.h}
+
+\section{Problemas}
+\subsection{Rainhas no tabuleiro*}
+
+\subsection{Jogo de Nim*}
+
+\subsection{Soma em subvetor*}
+
+\subsection{Remoção de valores com deque*}
+
+\subsection{Remoção de valores com lista*}
+
+\subsection{Embarcadouro*}
+
+\section{Algoritmos}
+\subsection{Ordenação por fusão*}
+\importsource{merge-sort.h}
+
+\subsection{Mochila com recuperação*}
+
+\subsection{Permutações*}
+
+\subsection{Algoritmo de Mo*}
+
+\subsection{Meet in the middle*}
+
+\subsection{Maior subsequência crescente*}
+\importsource{lis.cpp}
+
+\subsection{Maior subsequência crescente mais rápido*}
+\importsource{lisnlgn.cpp}
+
+\subsection{PD de perfil quebrado*}
+
+\subsection{Busca binária*}
 \importsource{binary-search.cpp}
 
+\subsection{Busca binária diferentona*}
+
+\subsection{Máscaras de bit e operações em bit*}
+\importsource{bit-ops.cpp}
+
 \end{document}
diff --git a/fontes/acs.h b/fontes/acs.h
new file mode 100644
index 0000000000000000000000000000000000000000..4357d14f88e0dda436c0135bdc5bc90b2506609e
--- /dev/null
+++ b/fontes/acs.h
@@ -0,0 +1,67 @@
+struct node {
+    int p, pc, depth, lnk, out, occ;
+    bool leaf;
+    vector<int> nxt, go, ix;
+
+    node() : p (0), pc (0), depth (-1),
+        lnk (-1), out (-1), occ (0),
+        leaf (false), nxt (S, -1), go (S, -1) {}
+};
+
+vector<node> aca (1);
+void ins(string ne, int ix) {
+    int u = 0;
+    for (int i = 0; i < ne.size(); i++) {
+        int ch = to_i(ne[i]);
+        if (aca[u].nxt[ch] == -1) {
+            aca[u].nxt[ch] = aca.size();
+            node n; n.p = u; n.pc = ch; n.depth = i;
+            aca.push_back(n);
+        }
+        u = aca[u].nxt[ch];
+    }
+    aca[u].leaf = true;
+    aca[u].ix.push_back(ix);
+}
+
+int go(int u, int c);
+
+int link(int u) {
+    if (aca[u].lnk != -1) { return aca[u].lnk; }
+    if (u == 0 || aca[u].p == 0) { return aca[u].lnk = 0; }
+    return aca[u].lnk = go(link(aca[u].p), aca[u].pc);
+}
+
+int go(int u, int c) {
+    if (aca[u].go[c] != -1) { return aca[u].go[c]; }
+    if (aca[u].nxt[c] != -1)
+        return aca[u].go[c] = aca[u].nxt[c];
+    if (u == 0) { return aca[u].go[c] = 0; }
+    return aca[u].go[c] = go(link(u), c);
+}
+
+int out(int u) {
+    if (aca[u].out != -1) { return aca[u].out; }
+    int v = link(u);
+    if (v == 0 || aca[v].leaf) { return aca[u].out = v; }
+    return aca[u].out = out(v);
+}
+
+vector<int> occ (N); vector<vector<int>> occix (N);
+void process(string hay) {
+    int u = 0;
+    for (int i = 0; i < hay.size(); i++) {
+        int ch = to_i(hay[i]);
+        u = go(u, ch);
+        for (int v = u; v != 0; v = out(v)) {
+            for (auto ix : aca[v].ix)
+                // match at (i - aca[v].depth), O(len + ans)
+                occix[ix].push_back(i - aca[v].depth);
+            aca[v].occ++;
+        }
+    }
+    for (int u = 0; u < aca.size(); u++)
+        for (auto ix : aca[u].ix)
+            // number of matches, O(len)
+            occ[ix] += aca[u].occ;
+}
diff --git a/fontes/aho-cora-sick.cpp b/fontes/aho-cora-sick.cpp
deleted file mode 100644
index 3a74c2a655f249a80dbac448f8e172d891ccfe1c..0000000000000000000000000000000000000000
--- a/fontes/aho-cora-sick.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-struct node {
-  int p = 0, pc = 0;
-  int oix = -1, lnk = -1, out = -1;
-  bool leaf = false;
-  vector<int> nxt = vector<int>(256, -1);
-  vector<int> go = vector<int>(256, -1);
-  vector<int> ix;
-  int occ;
-};
-
-vector<node> aca = { node() };
-vector<vector<int>> occ (100000+15);
-
-void insert(string needle, int ix) {
-  int u = 0;
-  for (int i = 0; i < needle.size(); i++) {
-    int ch = to_i(needle[i]);
-    if (aca[u].nxt[ch] == -1) {
-      aca[u].nxt[ch] = aca.size();
-      node n; n.p = u; n.pc = ch; n.oix = i;
-      aca.push_back(n);
-    }
-    u = aca[u].nxt[ch];
-  }
-  aca[u].leaf = true;
-  aca[u].ix.push_back(ix);
-}
-
-int go(int u, int c);
-
-int link(int u) {
-  if (aca[u].lnk != -1) { return aca[u].lnk; }
-  if (u == 0 || aca[u].p == 0) { return aca[u].lnk = 0; }
-  return aca[u].lnk = go(link(aca[u].p), aca[u].pc);
-}
-
-int go(int u, int c) {
-  if (aca[u].go[c] != -1) { return aca[u].go[c]; }
-  if (aca[u].nxt[c] != -1) { return aca[u].go[c] = aca[u].nxt[c]; }
-  if (u == 0) { return aca[u].go[c] = 0; }
-  return aca[u].go[c] = go(link(u), c);
-}
-
-int out(int u) {
-  if (aca[u].out != -1) { return aca[u].out; }
-  int v = link(u);
-  if (v == 0 || aca[v].leaf) { return aca[u].out = v; }
-  return aca[u].out = out(v);
-}
-
-void process(string haystack) {
-  int u = 0;
-  for (int i = 0; i < haystack.size(); i++) {
-    int ch = to_i(haystack[i]);
-    u = go(u, ch);
-    for (int v = u; v != 0; v = out(v)) {
-      for (auto ix : aca[v].ix) {
-        // match at (i - aca[v].oix), O(len + ans)
-        occ[ix].push_back(i - aca[v].oix);
-      }
-      aca[v].occ++;
-    }
-  }
-  for (int u = 0; u < aca.size(); u++) {
-    for (auto ix : aca[v].ix) {
-      // number of matches, O(len)
-      occ[ix] += aca[u].occ;
-    }
-  }
-}
diff --git a/fontes/angular-sweep.cpp b/fontes/angular-sweep.cpp
deleted file mode 100644
index 2c00d469bbb0903f5535787e58fe6ac4542841ee..0000000000000000000000000000000000000000
--- a/fontes/angular-sweep.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-int get_points_inside (int i, double radius, int N) {
-  vector<db> angles;
-
-  for (int j = 0; j < N; j++) if (i != j && distances[i][j] <= 2*radius) {
-    double A = atan2(points[j].yy - points[i].yy, points[j].xx - points[i].xx);
-    double B = acos(distances[i][j]/(2*radius));
-    angles.push_back(dbi(A - B, j));
-    angles.push_back(dbi(A + B, j));
-  }
-
-  sort(angles.begin(), angles.end());
-
-  int count = 1, res = 1;
-  for (auto angle : angles) {
-    count += angle.second ? 1 : -1;
-    res = max(res, count);
-  }
-
-  return res;
-}
diff --git a/fontes/angular-sweep.h b/fontes/angular-sweep.h
new file mode 100644
index 0000000000000000000000000000000000000000..0eee34be1519a0230ae60ff3646f7a1a66b26444
--- /dev/null
+++ b/fontes/angular-sweep.h
@@ -0,0 +1,20 @@
+int get_points_inside (int i, double r, int n) {
+  vector<double> ang;
+  for (int j = 0; j < n; j++)
+    if (i != j && d[i][j] <= 2*r) {
+      double a = atan2(p[j].py - p[i].py, p[j].px - p[i].px);
+      double b = acos(d[i][j]/(2*r));
+      ang.push_back(dbi(a - b, j));
+      ang.push_back(dbi(a + b, j));
+    }
+
+  sort(ang.begin(), ang.end());
+
+  int count = 1, res = 1;
+  for (auto angle : ang) {
+    count += angle.second ? 1 : -1;
+    res = max(res, count);
+  }
+
+  return res;
+}
diff --git a/fontes/articbridges.h b/fontes/articbridges.h
new file mode 100644
index 0000000000000000000000000000000000000000..46d17b9c6891265716f4dbcca95826df1914c304
--- /dev/null
+++ b/fontes/articbridges.h
@@ -0,0 +1,18 @@
+int tk = 0; vector<int> tin (N, -1), low (N);
+vector<ii> brid; set<int> arti;
+
+void dfs(int u, int p) {
+  tin[u] = low[u] = tk++; int ch = 0;
+  for (auto v : g[u]) {
+    if (v == p) continue;
+    else if (tin[v] == -1) {
+      dfs(v, u); ch++;
+      if ((low[v] >= tin[u] && p != u) ||
+          (ch >= 2 && p == u))
+        arti.insert(u);
+      if (low[v] > tin[u])
+        brid.push_back(ii(u, v));
+      low[u] = min(low[u], low[v]);
+    } else { low[u] = min(low[u], tin[v]); }
+  }
+}
diff --git a/fontes/articulations-and-bridges.cpp b/fontes/articulations-and-bridges.cpp
deleted file mode 100644
index 69b9a7835486b0ee5e1dfa1a84cdb216986eca84..0000000000000000000000000000000000000000
--- a/fontes/articulations-and-bridges.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-vector<bool> visited (N, false);
-vector<int> parent (N, -1);
-vector<int> low (N);
-vector<int> tin (N);
-vector<ii> brid;
-set<int> arti;
-
-void dfs(int u) {
-  int children = 0;
-  visited[u] = true;
-
-  for (int v : graph[u]) if (!visited[v]) {
-    children++;
-    parent[v] = u;
-
-    low[v] = tin[v] = tin[u] + 1;
-    dfs(v);
-    low[u] = min(low[u], low[v]);
-
-    if ((parent[u] == -1 && children > 1) ||
-        (parent[u] != -1 && low[v] >= tin[u]))
-      arti.insert(u);
-
-    if (low[v] > tin[u])
-      brid.push_back(ii(u, v));
-
-  } else if (parent[u] != v) {
-    low[u] = min(low[u], tin[v]);
-  }
-}
-
-for (int u = 0; u < n; u++) if (!visited[u]) {
-  tin[u] = 0;
-  dfs(u);
-}
diff --git a/fontes/bashrc b/fontes/bashrc
index 444c3483ddfa38448afbb77f65b1e82b3ef5c6b3..6e16fbe52693471332682aeae5cf71b4435d73e3 100644
--- a/fontes/bashrc
+++ b/fontes/bashrc
@@ -1,9 +1,9 @@
 xmodmap -e 'clear lock' -e 'keycode 66=Escape'
 alias e=vim
 function bc {
-    boca-submit-run user password $1 C++17 $1.cpp
+  boca-submit-run user password $1 C++17 $1.cpp
 }
 alias bs='boca-submit-run user password'
 function c {
-    g++ -static -O2 -lm $1 && ./a.out
+  g++ -static -O2 -lm $1 && ./a.out
 }
diff --git a/fontes/bfs.h b/fontes/bfs.h
new file mode 100644
index 0000000000000000000000000000000000000000..97c924bb8cc97d5cbb593facfa1d5f49ac7476b7
--- /dev/null
+++ b/fontes/bfs.h
@@ -0,0 +1,14 @@
+int explore(int u) {
+    int c = 0;
+    queue<int> q;
+    q.push(u);
+    while (!q.empty()) {
+        int u = q.front(); q.pop();
+        for (int v : g[u]) if (!visited[v]) {
+            c++;
+            visited[v] = true;
+            q.push(v);
+        }
+    }
+    return c;
+}
diff --git a/fontes/bfs01.h b/fontes/bfs01.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccb136133291fc23fc7e8f9bb9fe413ba60b40cd
--- /dev/null
+++ b/fontes/bfs01.h
@@ -0,0 +1,20 @@
+vector<int> d (N, oo);
+
+void bfs01(int s) {
+    d[s] = 0;
+    deque<int> q;
+    q.push_front(s);
+    while (!q.empty()) {
+        int u = q.front();
+        q.pop_front();
+        for (auto [v, w] : g[u]) {
+            if (d[u] + w < d[v]) {
+                d[v] = d[u] + w;
+                if (w == 1)
+                    q.push_back(v);
+                else
+                    q.push_front(v);
+            }
+        }
+    }
+}
diff --git a/fontes/fast-pow.cpp b/fontes/binary-pow.h
similarity index 100%
rename from fontes/fast-pow.cpp
rename to fontes/binary-pow.h
diff --git a/fontes/bllca.h b/fontes/bllca.h
new file mode 100644
index 0000000000000000000000000000000000000000..4bcd8b2e9966c3c319b5c500617103e7b0f88c14
--- /dev/null
+++ b/fontes/bllca.h
@@ -0,0 +1,10 @@
+int bl_lca(int a, int b) {
+    if (!(depth[b] < depth[a])) { swap(a, b); }
+    int diff = depth[a] - depth[b];
+    for (int l = L; l >= 0; l--) if (diff & (1 << l))
+        a = up[a][l];
+    if (a == b) { return a; }
+    for (int l = L; l >= 0; l--) if (up[a][l] != up[b][l])
+        a = up[a][l], b = up[b][l];
+    return up[a][0];
+}
diff --git a/fontes/catalan.cpp b/fontes/catalan.h
similarity index 100%
rename from fontes/catalan.cpp
rename to fontes/catalan.h
diff --git a/fontes/convex-hull.cpp b/fontes/convex-hull.cpp
deleted file mode 100644
index d455b8a6ac5fcce45e064b503bd9058b78020fd6..0000000000000000000000000000000000000000
--- a/fontes/convex-hull.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-int sgn (double v) { return (v > 0) - (v < 0); }
-// -1 (cw), 0 (colinear), +1 (ccw)
-int seg_ornt (pt a, pt b, pt c) {
-  return sgn(cross(vec(a, b), vec(a, c)));
-}
-
-// doesn't include collinear points (<= -> < to include)
-vpt convex_hull /* O(n lg n) */ (vpt& ps) {
-  int k = 0, n = ps.size();
-  vpt result (n * 2);
-
-  sort(all(ps), [](pt a, pt b) {
-    return mp(a.px, a.py) < mp(b.px, b.py);
-  });
-
-  for (int i = 0; i < n; i++) {
-    while (k >= 2 && seg_ornt( /* lower hull */
-        result[k-2], result[k-1], ps[i]) <= 0) k--;
-    result[k++] = ps[i];
-  }
-
-  for (int i = n - 2, t = k + 1; i >= 0; i--) {
-    while (k >= t && seg_ornt( /* upper hull */
-        result[k-2], result[k-1], ps[i]) <= 0) k--;
-    result[k++] = ps[i];
-  }
-
-  result.resize(k - 1);
-  return result;
-}
diff --git a/fontes/custom-hash.cpp b/fontes/custom-hash.h
similarity index 100%
rename from fontes/custom-hash.cpp
rename to fontes/custom-hash.h
diff --git a/fontes/dfs.cpp b/fontes/dfs.cpp
deleted file mode 100644
index 4ec532c36a7d0219fe43b922b93e8f9fe0d4a420..0000000000000000000000000000000000000000
--- a/fontes/dfs.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-int dfs (int u, int parent, int dest, int w) {
-  if (u == dest) { return w; }
-
-  for (auto e : prim_graph[u]) if (e.vv != parent) {
-    int returned_weight = dfs(e.vv, u, dest, e.ww);
-    if (returned_weight != -oo) { return max(returned_weight, w); }
-  }
-
-  return -oo;
-}
-
-int find_max_weight (int u, int v) {
-  if (u == v) { return 0; }
-  return dfs(u, -1, v, -oo);
-}
diff --git a/fontes/dfsrec.h b/fontes/dfsrec.h
new file mode 100644
index 0000000000000000000000000000000000000000..04b2dde8d72ce281d6fda4336e2d19bb21d1628d
--- /dev/null
+++ b/fontes/dfsrec.h
@@ -0,0 +1,7 @@
+int explore(int u) {
+    visited[u] = true;
+    int c = 1;
+    for (int v : g[u]) if (!visited[v])
+        c += explore(v);
+    return c;
+}
diff --git a/fontes/dfsstack.h b/fontes/dfsstack.h
new file mode 100644
index 0000000000000000000000000000000000000000..3b8e6be2b217a36f1beb502b127b3b864ea1f73e
--- /dev/null
+++ b/fontes/dfsstack.h
@@ -0,0 +1,14 @@
+int explore(int u) {
+    int c = 0;
+    stack<int> s;
+    s.push(u);
+    while (!s.empty()) {
+        int u = s.top(); s.pop();
+        for (int v : g[u]) if (!visited[v]) {
+            c++;
+            visited[v] = true;
+            s.push(v);
+        }
+    }
+    return c;
+}
diff --git a/fontes/dijkstra.cpp b/fontes/dijkstra.cpp
deleted file mode 100644
index bc007100d852d2fc3919a7caaaf819c4435b81a2..0000000000000000000000000000000000000000
--- a/fontes/dijkstra.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-vvii graph (N);
-vi dist (N);
-vector<bool> visited (N);
-
-int dijkstra (int source, int destination, int n) {
-  fill(dist.begin(), dist.begin() + n, oo);
-  fill(visited.begin(), visited.begin() + n, false);
-  priority_queue<ii, vii, greater<ii>> Q;
-
-  dist[source] = 0;
-  Q.push({0, source});
-
-  while (!Q.empty()) {
-    int u = Q.top().uu; Q.pop();
-    if (visited[u]) { continue; }
-    visited[u] = true;
-
-    for (auto e : invgraph[u]) {
-      int v = e.vv, w = e.ww;
-      if (dist[u] == dist[v] + w) {
-        dag[v].push_back(u);
-      }
-    }
-
-    if (u == destination) { break; }
-
-    for (auto e : graph[u]) {
-      int v = e.vv, w = e.ww;
-      if (dist[v] > dist[u] + w) {
-        dist[v] = dist[u] + w;
-        Q.push({dist[v], v});
-      }
-    }
-  }
-
-  return dist[destination];
-}
diff --git a/fontes/dijkstra.h b/fontes/dijkstra.h
new file mode 100644
index 0000000000000000000000000000000000000000..e70b8f22ee579ddb6994faf26b09f92777958520
--- /dev/null
+++ b/fontes/dijkstra.h
@@ -0,0 +1,22 @@
+vector<ll> d (N); vector<bool> vis (N);
+vector<vector<int>> dag (N);
+void dijkstra(int src, int dest) {
+  fill(d.begin(), d.end(), oo);
+  fill(vis.begin(), vis.end(), false);
+  priority_queue<ii, vector<ii>, greater<ii>> Q;
+  d[src] = 0;
+  Q.push({0, src});
+  while (!Q.empty()) {
+    auto [c, u] = Q.top(); Q.pop();
+    if (vis[u]) { continue; }
+    vis[u] = true;
+    for (auto [v, w] : gt[u]) if (d[u] == d[v] + w)
+      dag[v].push_back(u);
+    if (u == dest) { break; }
+    for (auto [v, w] : g[u])
+      if (d[v] > d[u] + w) {
+        d[v] = d[u] + w;
+        Q.push({d[v], v});
+      }
+  }
+}
diff --git a/fontes/diophantine.h b/fontes/diophantine.h
new file mode 100644
index 0000000000000000000000000000000000000000..cf3818bf1a5e666db8c7b942df582fb45c744e05
--- /dev/null
+++ b/fontes/diophantine.h
@@ -0,0 +1,11 @@
+vector<ii> solve(ll a, ll b, ll c, int i) {
+  vector<ii> sol;
+  ll x, y, g = extgcd(a, b, x, y);
+  if (c % g) { return; }
+  x *= c/g; y *= c/g;
+  while (i--) {
+    sol.push_back(ii(x, y));
+    x += b/g; y -= a/g;
+  }
+  return sol;
+}
diff --git a/fontes/disjoint.h b/fontes/disjoint.h
new file mode 100644
index 0000000000000000000000000000000000000000..877e533aeb07b961286840f99bdaa59e3ef6ecee
--- /dev/null
+++ b/fontes/disjoint.h
@@ -0,0 +1,21 @@
+vector<int> rep (N), rnk (N), siz (N);
+
+int ds_find(int u) {
+  if (rep[u] != u) { rep[u] = ds_find(rep[u]); }
+  return rep[u];
+}
+
+void ds_unite(int u, int v) {
+  u = ds_find(u); v = ds_find(v);
+  assert(u != v);
+  if (!(rnk[u] > rnk[v])) { swap(u, v); }
+  if (rnk[u] == rnk[v]) { rnk[u]++; }
+  rep[v] = u;
+  siz[u] += siz[v];
+}
+
+void ds_init(int n) {
+    for (int u = 0; u < n; u++) {
+        rep[u] = u; rnk[u] = 0; siz[u] = 1;
+    }
+}
diff --git a/fontes/euler-totient.cpp b/fontes/euler-totient.h
similarity index 100%
rename from fontes/euler-totient.cpp
rename to fontes/euler-totient.h
diff --git a/fontes/extended-gcd.cpp b/fontes/extended-gcd.cpp
deleted file mode 100644
index 3da06f5c4ffc08a3fc436cc58abfe99912521e4b..0000000000000000000000000000000000000000
--- a/fontes/extended-gcd.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// ax + by = gcd(a, b)
-// ax = gcd(a, b) (mod b)
-// (gcd(a, b) = 1) => (ax = 1 (mod b))
-//
-// Time: O(lg min(a, b))
-// Space: O(1)
-struct gans { ll x, y, d; };
-gans ext_gcd(ll a, ll b) {
-  if (a == 0) return { 0, 1, b };
-  gans e = ext_gcd(b % a, a);
-  return { e.y - (b/a)*e.x, e.x, e.d };
-}
diff --git a/fontes/extgcd.h b/fontes/extgcd.h
new file mode 100644
index 0000000000000000000000000000000000000000..7340bebf2a3618d5c675b8ff7e33660b54dfbe90
--- /dev/null
+++ b/fontes/extgcd.h
@@ -0,0 +1,11 @@
+ll extgcd(ll a, ll b, ll& x, ll& y) {
+  if (b == 0) { x = 1; y = 0; return a; }
+  ll g = extgcd(b, a%b, x, y);
+  tie(x, y) = make_tuple(y, x - (a/b)*y);
+  return g;
+}
+
+ll inv(ll a, ll m) {
+  ll x, y; extgcd(a, m, x, y);
+  return ((x % m) + m) % m;
+}
diff --git a/fontes/factorize.cpp b/fontes/factorize.cpp
deleted file mode 100644
index b76865e289d7fbc4e872d173705ceb8525495502..0000000000000000000000000000000000000000
--- a/fontes/factorize.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-void factorize(ll n) {
-  for (ll i = 2; i*i <= n; i++) {
-    while (n % i == 0) {
-      // process divisor
-      n /= i;
-    }
-  }
-  if (n > 1) {
-    // process n
-  }
-}
diff --git a/fontes/factorize.h b/fontes/factorize.h
new file mode 100644
index 0000000000000000000000000000000000000000..1cf040c3dd97634b32f6b9ced3709f84ec197615
--- /dev/null
+++ b/fontes/factorize.h
@@ -0,0 +1,11 @@
+vector<int> factorize(ll n) {
+  vector<int> v;
+  for (ll i = 2; i*i <= n; i++)
+    while (n % i == 0) {
+      n /= i;
+      v.push_back(i);
+    }
+  if (n > 1)
+    v.push_back(n);
+  return v;
+}
diff --git a/fontes/fenwick-2d-tree.cpp b/fontes/fenwick-2d-tree.cpp
deleted file mode 100644
index a2f401fd251835f35569000d109ab73bcc2afea5..0000000000000000000000000000000000000000
--- a/fontes/fenwick-2d-tree.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-vvi ftree(ftN, vi(ftM, 0)); // 1-indexed
-
-void ft_add /* O(lg^2 n) */ (int x,int y,int d) {
-  for (; x < ftN; x += x & -x)
-  for (int j = y; j < ftM; j += j & -j)
-    ftree[x][j] += d;
-}
-
-int ft_rsq_upto /* O(lg^2 n) */ (int x, int y) {
-  int sum = 0;
-  for (; x > 0; x -= x & -x)
-  for (int j = y; j > 0; j -= j & -j)
-    sum += ftree[x][j];
-  return sum;
-}
-
-int ft_rsq /* O(lg^2 n) */ (
-    int x1, int y1, int x2, int y2) {
-  return ft_rsq_upto(x2, y2)
-    - ft_rsq_upto(x2, y1 - 1)
-    - ft_rsq_upto(x1 - 1, y2)
-    + ft_rsq_upto(x1 - 1, y1 - 1);
-}
diff --git a/fontes/fenwick-2d-tree.h b/fontes/fenwick-2d-tree.h
new file mode 100644
index 0000000000000000000000000000000000000000..044009d1548633d21fc50f78ad7fa5c983d3abdc
--- /dev/null
+++ b/fontes/fenwick-2d-tree.h
@@ -0,0 +1,20 @@
+vector<vector<ll>> bit (N, vector<ll>(M));
+
+void add(int x, int y, ll d) {
+  for (; x < N; x += x & -x)
+  for (int j = y; j < M; j += j & -j)
+    bit[x][j] += d;
+}
+
+ll pref(int x, int y) {
+  ll sum = 0;
+  for (; x > 0; x -= x & -x)
+  for (int j = y; j > 0; j -= j & -j)
+    sum += bit[x][j];
+  return sum;
+}
+
+ll sum_inclusive(int x1, int y1, int x2, int y2) {
+  return pref(x2, y2) - pref(x2, y1 - 1)
+    - pref(x1 - 1, y2) + pref(x1 - 1, y1 - 1);
+}
diff --git a/fontes/fenwick-range-tree.cpp b/fontes/fenwick-range-tree.cpp
deleted file mode 100644
index b9a0c753535dc161a91cddcd1567b90cb96ec079..0000000000000000000000000000000000000000
--- a/fontes/fenwick-range-tree.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-int ftN = 4*N; // O(n)
-vi tree_a = vi(ftN, 0); // 1-indexed
-vi tree_b = vi(ftN, 0); // 1-indexed
-
-// copy add and query
-
-int prefix_sum (int i) {
-  return query(tree_a, i) * i - query(tree_b, i);
-}
-
-int range_sum (int i, int j) {
-  return prefix_sum(j) - prefix_sum(i - 1);
-}
-
-void range_add (int a, int b, int d) {
-  add(tree_a, a, d);
-  add(tree_b, a, d * (a - 1));
-  add(tree_a, b + 1, -d);
-  add(tree_b, b + 1, -d * b);
-}
diff --git a/fontes/fenwick-range-tree.h b/fontes/fenwick-range-tree.h
new file mode 100644
index 0000000000000000000000000000000000000000..a8d6142c8b53cb41b81c80bc4f17f85e3993e588
--- /dev/null
+++ b/fontes/fenwick-range-tree.h
@@ -0,0 +1,26 @@
+vector<ll> bit1 (N), bit2 (N);
+
+void add(vector<ll>& bit, int i, ll d) {
+  for (; i < N; i += i & -i) { bit[i] += d; }
+}
+
+ll pref(vector<ll>& bit, int i) {
+  ll sum = 0;
+  for (; i > 0; i -= i & -i) { sum += bit[i]; }
+  return sum;
+}
+
+ll pref(int i) {
+  return pref(bit1, i) * i - pref(bit2, i);
+}
+
+ll sum_inclusive(int i, int j) {
+  return pref(j) - pref(i - 1);
+}
+
+void add_inclusive(int a, int b, ll d) {
+  add(bit1, a, d);
+  add(bit2, a, d * (a - 1));
+  add(bit1, b + 1, -d);
+  add(bit2, b + 1, -d * b);
+}
diff --git a/fontes/fenwick-tree.cpp b/fontes/fenwick-tree.cpp
deleted file mode 100644
index 58bbe39e40d2346e2fd28ed69791bf6d2d7312e8..0000000000000000000000000000000000000000
--- a/fontes/fenwick-tree.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-int ft_n = N; // O(n)
-vi ftree(ft_n, 0); // 1-indexed
-
-void add /* O(lg n) */ (int i, int d) {
-  for (; i < ft_n; i += i & -i)
-    ftree[i] += d;
-}
-
-int query /* O(lg n) */ (int i) {
-  int sum = 0;
-  for (; i > 0; i -= i & -i)
-    sum += ftree[i];
-  return sum;
-}
-
-// 1: add + range_sum, query is query_upto
-int query_inclusive /* O(lg n) */ (int i, int j) {
-  return query(j) - query(i - 1);
-}
-
-// 2: range_add + query, query is query
-void add_inclusive (int a, int b, int d) {
-  add(a, d);
-  add(b + 1, -d);
-}
diff --git a/fontes/fenwick-tree.h b/fontes/fenwick-tree.h
new file mode 100644
index 0000000000000000000000000000000000000000..bebaeef12e896ac8b45ce90238525e1ed12368ce
--- /dev/null
+++ b/fontes/fenwick-tree.h
@@ -0,0 +1,20 @@
+vector<ll> bit (N, 0);
+
+void add(int i, ll d) {
+  for (; i < N; i += i & -i) { bit[i] += d; }
+}
+
+ll pref(int i) {
+  int sum = 0;
+  for (; i > 0; i -= i & -i) { sum += bit[i]; }
+  return sum;
+}
+
+int sum_inclusive(int i, int j) {
+  return pref(j) - pref(i - 1);
+}
+
+void add_inclusive(int a, int b, ll d) {
+  add(a, d);
+  add(b + 1, -d);
+}
diff --git a/fontes/ffekbfs.h b/fontes/ffekbfs.h
new file mode 100644
index 0000000000000000000000000000000000000000..56fcaa22ba0d06b68d9706b099399c8e1ddffa35
--- /dev/null
+++ b/fontes/ffekbfs.h
@@ -0,0 +1,18 @@
+vector<int> ix (N), dist (N), par (N);
+bool minimum_path(int s, int t) {
+  fill(dist.begin(), dist.end(), oo); dist[s] = 0;
+  queue<int> q; q.push(s);
+  while (!q.empty()) {
+    int u = q.front(); q.pop();
+    if (u == t) { break; }
+    for (int i : res[u]) {
+      edge e = edges[i]; int v = e.v;
+      if (e.cap && dist[v] == oo) {
+        dist[v] = dist[u] + 1;
+        par[v] = u; ix[v] = i;
+        q.push(v);
+      }
+    }
+  }
+  return dist[t] < oo;
+}
diff --git a/fontes/ffekspfa.h b/fontes/ffekspfa.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d6a97b4326042f8c88cdc8a76f5817dd192c827
--- /dev/null
+++ b/fontes/ffekspfa.h
@@ -0,0 +1,18 @@
+vector<int> queu (N), ix (N), dist (N), par (N);
+bool minimum_path(int s, int t) {
+    fill(dist.begin(), dist.end(), oo); dist[s] = 0;
+    queue<int> q; q.push(s);
+    while (!q.empty()) {
+        int u = q.front(); q.pop();
+        queu[u] = 0;
+        for (int i : res[u]) {
+            edge e = edges[i]; int v = e.v;
+            if (e.cap && dist[v] > dist[u] + e.cost) {
+                dist[v] = dist[u] + e.cost;
+                par[v] = u; ix[v] = i;
+                if (!queu[v]) { q.push(v); queu[v] = 1; }
+            }
+        }
+    }
+    return dist[t] < oo;
+}
diff --git a/fontes/floyd.h b/fontes/floyd.h
new file mode 100644
index 0000000000000000000000000000000000000000..586099bfc2e6275a05da81ebd06af14ab2abeff8
--- /dev/null
+++ b/fontes/floyd.h
@@ -0,0 +1,14 @@
+struct cyc { ll prev, first, len; };
+cyc find_cycle(ll start) {
+    ll a = start, b = start;
+    do {
+        a = succ(a);
+        b = succ(succ(b));
+    } while (a != b);
+    a = start;
+    ll prev = -1;
+    while (a != b) { prev = a; a = succ(a); b = succ(b); }
+    ll len = 0;
+    do { b = succ(b); len++; } while (a != b);
+    return { .prev = prev, .first = a, .len = len };
+}
diff --git a/fontes/floydhash.h b/fontes/floydhash.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0a3fade7b4eaf7ba16007efaddfa826dc0cc988
--- /dev/null
+++ b/fontes/floydhash.h
@@ -0,0 +1,16 @@
+ll polyhash(string const& s) {
+    ll h = 0, p = 1;
+    for (char c : s) {
+        h += (c-'a'+1) * p; h %= M;
+        p *= P; p %= M; }
+    return h;
+}
+string gen(ll u) {
+    mt19937_64 rnd (u); u = rnd();
+    string s;
+    while (u) { s += ('a'+(u%26)); u /= 26; }
+    return s;
+}
+ll succ(ll u) {
+    return polyhash(gen(u));
+}
diff --git a/fontes/geometry.cpp b/fontes/geometry.h
similarity index 97%
rename from fontes/geometry.cpp
rename to fontes/geometry.h
index 32f0a749583bff8c71125901406ac2406d9be9c8..5205be47cab64d9b6e3d100b1b7acdda518d7375 100644
--- a/fontes/geometry.cpp
+++ b/fontes/geometry.h
@@ -59,7 +59,7 @@ double distance_seg_seg(seg s, seg t) {
   return min({ v1, v2, v3, v4 });
 }
 
-bool is_inside_poly(vector<pt>& ps, pt p) {
+bool is_inside_poly(vector<pt>& ps, pt p, bool strict) {
   int n = ps.size();
   if (n < 3) { return false; }
   int count = 0;
diff --git a/fontes/graham.h b/fontes/graham.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c488d128d77d10d5e72700ac748b8b6a3c5aeab
--- /dev/null
+++ b/fontes/graham.h
@@ -0,0 +1,22 @@
+vector<pt> convex_hull(vector<pt>& ps, bool col = false) {
+  pt p0 = *min_element(ps.begin(), ps.end(), [](pt a, pt b) {
+    return make_pair(a.py, a.px) < make_pair(b.py, b.px);
+  });
+  sort(ps.begin(), ps.end(), [&p0](pt a, pt b) {
+    int o = seg_ornt(p0, a, b);
+    return o < 0 || (o == 0 && norm(p0 - a) < norm(p0 - b));
+  });
+  if (col) {
+    int i = ps.size(); i--;
+    while (i >= 0 && seg_ornt(p0, ps[i], ps.back()) == 0)
+      i--;
+    reverse(ps.begin()+i+1, ps.end());
+  }
+  vector<pt> ans; for (int i = 0; i < ps.size(); i++) {
+    while (ans.size() > 1 && !ccw(
+        ps[i], ans.back(), ans[ans.size()-2], col))
+      ans.pop_back();
+    ans.push_back(ps[i]);
+  }
+  return ans;
+}
diff --git a/fontes/grundy.cpp b/fontes/grundy.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6c6c092207e0dc140bdb298ca0b0f60526c614c3
--- /dev/null
+++ b/fontes/grundy.cpp
@@ -0,0 +1,21 @@
+#include <bits/stdc++.h>
+using namespace std;
+const int N = 1e6+15;
+#include "mexset.h"
+vector<int> g (N, -1);
+int main() {
+    mex m (N);
+    for (int n = 0; n <= 1226; n++) {
+        if (n == 1 || n == 2) { g[n] = 0; continue; }
+        for (int i = 1; i <= n/2; i++) if (i != n-i)
+            m.insert_mex(g[i] ^ g[n-i]);
+        g[n] = m.get_reset_mex();
+    }
+    int t; cin >> t; while (t--) {
+        int n; cin >> n;
+        if (n >= 1226)
+            cout << "first\n";
+        else
+            cout << (g[n] != 0 ? "first" : "second") << "\n";
+    }
+}
diff --git a/fontes/hash.sh b/fontes/hash.sh
new file mode 100644
index 0000000000000000000000000000000000000000..15e11b440b04044a88cac789e33e6aadc6c8f693
--- /dev/null
+++ b/fontes/hash.sh
@@ -0,0 +1,3 @@
+# Hash das linhas [l1, l2]
+sed -n $2','$3' p' $1 | sed '/^#w/d' | cpp -dD -P
+  -fpreprocessed | tr -d '[:space:]' | md5sum | cut -c-6
diff --git a/fontes/heavy-light-decomposition.cpp b/fontes/heavy-light-decomposition.cpp
deleted file mode 100644
index a3a2fd2f1d42b3f43d10e26f0f33d106ec8f77f9..0000000000000000000000000000000000000000
--- a/fontes/heavy-light-decomposition.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-vi heavy(N, -1), anc(N, -1);
-vi depth(N);
-
-int hld_fill /* O(V + E) */ (int u, int c) {
-  int w = 1, maxw = 0;
-  cost[u] = c;
-  for (auto v : graph[u]) {
-    if (v != anc[u]) {
-      anc[v] = u;
-      depth[v] = depth[u] + 1;
-      int cw = hld_fill(v);
-      w += cw;
-      if (cw > maxw) {
-        maxw = cw;
-        heavy[u] = v;
-      }
-    }
-  }
-  return w;
-}
-
-vi hds(N), ixs(N);
-
-int cix = 1;
-
-void hld /* O(n lg n) */ (int u, int h = 1) {
-  hds[u] = h;
-  origin[cix] = cost[u];
-  ixs[u] = cix++;
-
-  if (heavy[u] != -1)
-    hld(heavy[u], h); // continue chain
-
-  for (auto v : graph[u]) {
-    if (v != anc[u] && v != heavy[u])
-      hld(v, v); // new chain
-  }
-}
-
-ll hld_sum /* O(lg^2 n) */ (int u, int v) {
-  ll answer = 0;
-  for (; hds[u] != hds[v]; v = anc[hds[v]]) {
-    if (depth[hds[u]] > depth[hds[v]]) swap(u, v);
-    ll path_sum = query_inclusive(ixs[hds[v]], ixs[v]);
-    answer += path_sum;
-  }
-  if (depth[u] > depth[v]) swap(u, v);
-
-  // Remove +1 if values are associated with vertices
-  return answer + query_inclusive(ixs[u] + 1, ixs[v]);
-}
diff --git a/fontes/hld.h b/fontes/hld.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9fe87274900b617fa724fdef0171bb01451354f
--- /dev/null
+++ b/fontes/hld.h
@@ -0,0 +1,39 @@
+vector<int> hvy (N), par (N), dep (N), hds (N), ixs (N);
+vector<ll> wei (N), ori (N);
+int cix = 1;
+
+int hld_fill(int u, int p, int d = 0, ll w = 0) {
+  int s = 1, maxs = 0;
+  wei[u] = w; par[u] = p; dep[u] = d; hvy[u] = -1;
+  for (auto [v, w] : g[u]) if (v != p) {
+    int cs = hld_fill(v, u, d+1, w);
+    s += cs;
+    if (cs > maxs) { maxs = cs; hvy[u] = v; }
+  }
+  return s;
+}
+
+void hld(int u, int h) {
+  hds[u] = h;
+  ori[cix] = wei[u];
+  ixs[u] = cix++;
+  if (hvy[u] != -1)
+    hld(hvy[u], h); // continue chain
+  for (auto [v, w] : g[u]) if (v != par[u] && v != hvy[u])
+    hld(v, v); // new chain
+}
+
+ll hld_op(int u, int v, bool edge_wei = 1) {
+  ll ans = 0;
+  for (; hds[u] != hds[v]; v = par[hds[v]]) {
+    if (dep[hds[u]] > dep[hds[v]]) { swap(u, v); }
+    ans = OP(ans,
+        op_inclusive(ixs[hds[v]], ixs[v]));
+  }
+  if (dep[u] > dep[v]) { swap(u, v); }
+  return OP(ans, op_inclusive(ixs[u] + edge_wei, ixs[v]));
+}
+
+void hld_init(int u) {
+  cix = 1; hld_fill(u, u); hld(u, u); build(ori);
+}
diff --git a/fontes/inclusion-exclusion.cpp b/fontes/inclusion-exclusion.h
similarity index 100%
rename from fontes/inclusion-exclusion.cpp
rename to fontes/inclusion-exclusion.h
diff --git a/fontes/interval-set.h b/fontes/interval-set.h
new file mode 100644
index 0000000000000000000000000000000000000000..6368c3aac30bff72acd07da01a1a50b0988c2708
--- /dev/null
+++ b/fontes/interval-set.h
@@ -0,0 +1,38 @@
+struct itvl {
+  int a, b, c;
+  itvl(int _a, int _b, int _c)
+    : a(_a), b(_b), c(_c) {}
+  bool operator<(const itvl& o) const {
+    return ii(b, a) < ii(o.b, o.a);
+  }
+  bool operator<(const int& o) const {
+    return b < o;
+  }
+};
+
+set<itvl, less<>>& si;
+
+void ins_in(itvl in) {
+  auto it = si.lower_bound(in);
+  int a = in.a, b = in.b, c = in.c;
+  if (si.size() > 0 && it != si.begin()
+      && prev(it)->b+1 == a && prev(it)->c == c) {
+    auto prv = prev(it); int prva = prv->a;
+    si.erase(prv); a = prva;
+  }
+  if (it != si.end() && c == it->c && b+1 == it->a) {
+    int nxtb = it->b; si.erase(it); b = nxtb;
+  }
+  si.insert(itvl(a, b, c));
+}
+
+void upd_color(int a, int b, int c) {
+  auto it = si.lower_bound(b);
+  if (it != si.end()) {
+    itvl ori = *it;
+    si.erase(it);
+    if (ori.a < a) { ins_in(itvl(ori.a, a-1, v)); }
+    if (ori.b > b) { ins_in(itvl(b+1, ori.b, v)); }
+  }
+  ins_in(itvl(a, b, c));
+}
diff --git a/fontes/kd-tree.cpp b/fontes/kd-tree.cpp
deleted file mode 100644
index 957d27b9e3b80bd6fc9ce5b68124aef701ecfdf8..0000000000000000000000000000000000000000
--- a/fontes/kd-tree.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-int get_ii(ii pair, int index) {
-    if (index == 0) { return pair.xx; }
-    else { return pair.yy; }
-}
-
-class kdtree {
-  private:
-    struct node {
-      node(ii& p) : point(p), left(nullptr), right(nullptr) {}
-      double dist_sq(const ii& p) {
-        int dx = p.xx - point.xx;
-        int dy = p.yy - point.yy;
-        return dx*dx + dy*dy;
-      }
-      ii point;
-      node* left;
-      node* right;
-    };
-    node* root = nullptr;
-    vector<double> best;
-    vector<node> nodes;
-
-    struct node_cmp {
-      node_cmp(size_t _index) : index(_index) {}
-      bool operator()(const node& n1, const node& n2) {
-        return get_ii(n1.point, index) < get_ii(n2.point, index);
-      }
-      size_t index;
-    };
-
-    node* make_tree(size_t begin, size_t end, size_t index) {
-      if (end <= begin)
-        return nullptr;
-      size_t n = begin + (end - begin)/2;
-      nth_element(&nodes[begin], &nodes[n], &nodes[0] + end, node_cmp(index));
-      index = (index + 1) % 2;
-      nodes[n].left = make_tree(begin, n, index);
-      nodes[n].right = make_tree(n + 1, end, index);
-      return &nodes[n];
-    }
-
-    void nearest_k(node* root, const ii& point, size_t index, int k) {
-      if (root == nullptr)
-        return;
-      double d = root->dist_sq(point);
-      if (best.size() < k || d < best[best.size()-1]) {
-        best.push_back(d);
-        sort(best.begin(), best.end());
-        if (best.size() > k) { best.erase(best.begin() + k, best.end()); }
-      }
-      if (best.size() == 0)
-        return;
-      double dx = get_ii(root->point, index) - get_ii(point, index);
-      index = (index + 1) % 2;
-      nearest_k(dx > 0 ? root->left : root->right, point, index, k);
-      if (dx * dx >= best[best.size()-1])
-        return;
-      nearest_k(dx > 0 ? root->right : root->left, point, index, k);
-    }
-
-  public:
-    template<typename iterator>
-      kdtree(iterator begin, iterator end) : nodes(begin, end) {
-        root = make_tree(0, nodes.size(), 0);
-      }
-
-    double nearest_k(const ii& pt, int k) {
-      if (root == nullptr)
-        throw logic_error("tree is empty");
-      best.clear();
-      nearest_k(root, pt, 0, k);
-      double acc = 0;
-      for (int i = 0; i < best.size(); i++) {
-        acc += sqrt(best[i]);
-      }
-      return acc;
-    }
-};
diff --git a/fontes/kd-tree.h b/fontes/kd-tree.h
new file mode 100644
index 0000000000000000000000000000000000000000..2e62a459117c5e9b1c17f063bdeccb106d8dd7cf
--- /dev/null
+++ b/fontes/kd-tree.h
@@ -0,0 +1,73 @@
+int get_ii(pt pair, int ix) {
+    if (ix == 0) { return pair.px; }
+    else { return pair.py; }
+}
+
+class kdtree {
+  private:
+  struct node {
+    node(pt& p) : p(p), left(nullptr), right(nullptr) {}
+    double dist_sq(const pt& o) { return norm(o - p); }
+    pt p; node* left, *right;
+  };
+  node* root = nullptr;
+  vector<double> best;
+  vector<node> t;
+
+  struct node_cmp {
+    node_cmp(size_t _index) : ix(_index) {}
+    bool operator()(const node& n1, const node& n2) {
+      return get_ii(n1.point, ix) < get_ii(n2.point, ix);
+    }
+    size_t ix;
+  };
+
+  node* make_tree(size_t begin, size_t end, size_t ix) {
+    if (end <= begin)
+      return nullptr;
+    size_t n = begin + (end - begin)/2;
+    nth_element(&t[begin], &t[n], &t[0] + end, node_cmp(ix));
+    ix = (ix + 1) % 2;
+    t[n].left = make_tree(begin, n, ix);
+    t[n].right = make_tree(n + 1, end, ix);
+    return &t[n];
+  }
+
+  void nearest_k(node* r, const pt& p, size_t ix, int k) {
+    if (r == nullptr)
+      return;
+    double d = r->dist_sq(p);
+    if (best.size() < k || d < best[best.size()-1]) {
+      best.push_back(d);
+      sort(best.begin(), best.end());
+      if (best.size() > k)
+        best.erase(best.begin() + k, best.end());
+    }
+    if (best.size() == 0)
+      return;
+    double dx = get_ii(r->p, ix) - get_ii(p, ix);
+    ix = (ix + 1) % 2;
+    nearest_k(dx > 0 ? r->left : r->right, p, ix, k);
+    if (dx * dx >= best[best.size()-1])
+      return;
+    nearest_k(dx > 0 ? r->right : r->left, p, ix, k);
+  }
+
+  public:
+  template<typename iterator>
+    kdtree(iterator begin, iterator end) : t(begin, end) {
+      root = make_tree(0, t.size(), 0);
+    }
+
+  double nearest_k(const pt& p, int k) {
+    if (root == nullptr)
+      throw logic_error("tree is empty");
+    best.clear();
+    nearest_k(root, p, 0, k);
+    double acc = 0;
+    for (int i = 0; i < best.size(); i++) {
+      acc += sqrt(best[i]);
+    }
+    return acc;
+  }
+};
diff --git a/fontes/kmp.cpp b/fontes/kmp.cpp
deleted file mode 100644
index 292b78460ae40c9c420473080bcbe8a2d3046df4..0000000000000000000000000000000000000000
--- a/fontes/kmp.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include <bits/stdc++.h>
-using namespace std;
-
-// kmp_pre: O(m = |needle|)
-vector<int> kmp_pre(string needle) {
-  vector<int> backtrack(needle.size()+1);
-  backtrack[0] = -1;
-
-  int i = 0, j = -1;
-  while (i < needle.size()) {
-    while (j >= 0 && needle[i] != needle[j]) j = backtrack[j];
-    i++; j++;
-    backtrack[i] = j;
-  }
-
-  return backtrack;
-}
-
-// kmp_search: O(n + m = |haystack| + |needle|)
-// laço principal: O(n = |haystack|)
-void kmp_search(string haystack, string needle) {
-  vector<int> backtrack = kmp_pre(needle);
-
-  int i = 0, j = 0;
-  while (i < haystack.size()) {
-    while (j >= 0 && haystack[i] != needle[j]) j = backtrack[j];
-    i++; j++;
-    if (j == needle.size()) {
-      // match at (i - j)
-    }
-  }
-}
-
-int main() {
-    vector<int> t = kmp_pre("aabccaabccaabcc");
-    for (auto x : t) {
-        cout << x << " ";
-    }
-    cout << "\n";
-}
diff --git a/fontes/kmp.h b/fontes/kmp.h
new file mode 100644
index 0000000000000000000000000000000000000000..e47fbce076a37dff55479d39be61893dcc48cfd5
--- /dev/null
+++ b/fontes/kmp.h
@@ -0,0 +1,25 @@
+vector<int> pre(string ne) {
+    int n = ne.size();
+    vector<int> pi (n, 0);
+    for (int i = 1, j = 0; i < n; i++) {
+        while (j > 0 && ne[i] != ne[j]) { j = pi[j-1]; }
+        if (ne[i] == ne[j]) { j++; }
+        pi[i] = j;
+    }
+    return pi;
+}
+
+int search(string hay, string ne) {
+    vector<int> pi = pre(ne);
+    int c = 0;
+    for (int i = 0, j = 0; i < hay.size(); i++) {
+        while (j > 0 && hay[i] != ne[j]) { j = pi[j-1]; }
+        if (hay[i] == ne[j]) { j++; }
+        if (j == ne.size()) {
+            c++;
+            // match at (i-j+1)
+            j = pi[j-1];
+        }
+    }
+    return c;
+}
diff --git a/fontes/kruskal.cpp b/fontes/kruskal.cpp
deleted file mode 100644
index 35299cff36b3eb9145d08d52206e4aeb9b772392..0000000000000000000000000000000000000000
--- a/fontes/kruskal.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-typedef pair<int, pair<int, int>> edge;
-// edge -> e.cc, (e.uu.xx, e.uu.yy)
-
-vector<int> rep (n);
-vector<int> rnk (n);
-vector<int> siz (n, 1);
-vector<edge> edges;
-
-int ds_find(int u) {
-  if (rep[u] != u) { rep[u] = ds_find(rep[u]); }
-  return rep[u];
-}
-
-void ds_union(int u, int v) {
-  u = ds_find(u); v = ds_find(v);
-
-  assert(u != v);
-  if (!(rnk[u] > rnk[v])) { swap(u, v); }
-  if (rnk[u] == rnk[v]) { rnk[u]++; }
-  rep[v] = u;
-  siz[u] += siz[v];
-}
-
-int kruskal(int n) {
-  sort(edges.begin(), edges.end());
-  for (int u = 1; u <= n; u++) { rep[u] = u; rnk[u] = 0; }
-  int components = n;
-  int total_cost = 0;
-  for (int i = 0; i < edges.size() && components > 1; i++) {
-    int u = e.uu.xx;
-    int v = e.uu.yy;
-
-    if (ds_find(u) != ds_find(v)) {
-      ds_union(u, v);
-      components--;
-      total_cost += e.cc;
-    }
-  }
-  return components > 1 ? oo : total_cost;
-}
diff --git a/fontes/kruskal.h b/fontes/kruskal.h
new file mode 100644
index 0000000000000000000000000000000000000000..37b3bb40846ead256c3a3c226cd6a63ab872d774
--- /dev/null
+++ b/fontes/kruskal.h
@@ -0,0 +1,20 @@
+struct edge {
+    int u, v, w;
+    bool operator<(struct edge &o) { return w < o.w; }
+};
+
+int kruskal(int n) {
+    sort(edges.begin(), edges.end());
+    ds_init(n);
+    int components = n;
+    ll sum = 0;
+    for (auto [u, v, w] : edges) {
+        if (components == 1) { break; }
+        if (ds_find(u) != ds_find(v)) {
+            ds_union(u, v);
+            components--;
+            sum += w;
+        }
+    }
+    return sum;
+}
diff --git a/fontes/lazy-segment-tree.cpp b/fontes/lazy-segment-tree.cpp
deleted file mode 100644
index dc0fd497224102fa8088c4f777fc8423273f2e70..0000000000000000000000000000000000000000
--- a/fontes/lazy-segment-tree.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-#define LEFT 2*i
-#define RIGH 2*i+1
-
-struct node {
-  int data = 0;
-
-  node() {};
-  node(int x) { data = x; };
-
-  node operator+(const node& a) {
-    node n; n.data = a.data + data; return n;
-  };
-  node operator+=(const int& a) {
-    data += a; return *this;
-  };
-};
-
-const int N = 1e5+15;
-const int LOG = ceil(log2(N));
-
-struct dlta { int add = 0, set = -1; };
-
-vector<ll> stree(2*N), origin(N);
-vector<dlta> delta(2*N);
-
-ll apply(int i, dlta d, int sz) {
-    if (d.set != -1) {
-        stree[i] = d.set * sz;
-        delta[i] = { 0, d.set };
-    }
-    if (d.add != 0) {
-        stree[i] += d.add * sz;
-        delta[i].add += d.add;
-    }
-    return stree[i];
-}
-
-void pull(int p) {
-    for (int s = __builtin_ctz(p)+1; s < LOG; s++) {
-        int i = p >> s;
-        stree[i] = stree[LEFT] + stree[RIGH];
-    }
-}
-
-void push(int p) {
-    int sz = 1 << (LOG-1);
-    for (int s = LOG; s > 0; s--, sz /= 2) {
-        int i = p >> s;
-        apply(LEFT, delta[i], sz);
-        apply(RIGH, delta[i], sz);
-        delta[i] = {};
-    }
-}
-
-ll op_range(int l, int r, char op = '\0', ll x = 0) {
-    dlta d;
-    if (op == '+') { d.add = x; }
-    if (op == '=') { d.set = x; }
-    int tl = l += N, tr = r += N, sz = 1;
-    push(tl); push(tr);
-    ll ans = 0;
-    for (; l < r; l /= 2, r /= 2, sz *= 2) {
-        if (l & 1) ans += apply(l++, d, sz);
-        if (r & 1) ans += apply(--r, d, sz);
-    }
-    pull(tl); pull(tr);
-    return ans;
-}
-
-void build () {
-    for (int i = 0; i < N; i++)
-      stree[N+i] = origin[i];
-    for (int i = N-1; i > 0; i--)
-      stree[i] = stree[LEFT] + stree[RIGH];
-}
diff --git a/fontes/lstit.h b/fontes/lstit.h
new file mode 100644
index 0000000000000000000000000000000000000000..02cb98989ad21fa717c765e217a85f0255f9122e
--- /dev/null
+++ b/fontes/lstit.h
@@ -0,0 +1,71 @@
+const int L = ceil(log2(N));
+struct dlta { int add = 0, set = -1; };
+vector<ll> t (2*N); vector<dlta> delta (2*N);
+
+void build(vector<int>& src) {
+  for (int i = 1; i < src.size(); i++)
+    t[N+i] = src[i];
+  for (int ti = N-1; ti > 0; ti--)
+    t[ti] = OP(t[2*ti], t[2*ti+1]);
+}
+
+ll apply(int ti, dlta d, int sz) {
+  if (d.set != -1) {
+    t[ti] = ll(d.set) * FACTOR(sz);
+    delta[ti] = { 0, d.set };
+  }
+  if (d.add != 0) {
+    t[ti] += ll(d.add) * FACTOR(sz);
+    delta[ti].add += d.add;
+  }
+  return t[ti];
+}
+
+void pull(int i) {
+  for (int s = __builtin_ctz(i)+1; s < L; s++) {
+    int ti = i >> s;
+    t[ti] = OP(t[2*ti], t[2*ti+1]);
+  }
+}
+
+void push(int i) {
+  int sz = 1 << (L-1);
+  for (int s = L; s > 0; s--, sz /= 2) {
+    int ti = i >> s;
+    apply(2*ti, delta[ti], sz);
+    apply(2*ti+1, delta[ti], sz);
+    delta[ti] = {};
+  }
+}
+
+void apply_inclusive(int l, int r,
+    char op = '\0', ll x = 0) {
+  r++;
+  dlta d;
+  if (op == '+') { d.add = x; }
+  if (op == '=') { d.set = x; }
+  int tl = l += N, tr = r += N, sz = 1;
+  push(tl); push(tr);
+  for (; l < r; l /= 2, r /= 2, sz *= 2) {
+    if (l & 1) { apply(l++, d, sz); }
+    if (r & 1) { apply(--r, d, sz); }
+  }
+  pull(tl); pull(tr);
+}
+
+void add_inclusive(int l, int r, ll d) {
+  apply_inclusive(l, r, '+', d);
+}
+
+ll op_inclusive(int l, int r) {
+  r++;
+  int tl = l += N, tr = r += N, sz = 1;
+  push(tl); push(tr);
+  ll ans = NEUTRAL;
+  for (; l < r; l /= 2, r /= 2, sz *= 2) {
+    if (l & 1) ans = OP(ans, apply(l++, dlta(), sz));
+    if (r & 1) ans = OP(ans, apply(--r, dlta(), sz));
+  }
+  pull(tl); pull(tr);
+  return ans;
+}
diff --git a/fontes/lstrec.h b/fontes/lstrec.h
new file mode 100644
index 0000000000000000000000000000000000000000..a586194ceea378aa615ef178357109a165a20d29
--- /dev/null
+++ b/fontes/lstrec.h
@@ -0,0 +1,61 @@
+vector<ll> t (4*N), lazy (4*N), sety (4*N, -1);
+
+void build(vector<int>& src,
+    int ti=1, int tl=1, int tr=N) {
+  if (tl == tr) {
+    if (tl < src.size()) { t[ti] = src[tl]; }
+    return;
+  }
+  int tm = (tl + tr) / 2;
+  build(src, ti*2, tl, tm);
+  build(src, ti*2+1, tm+1, tr);
+  t[ti] = OP(t[ti*2], t[ti*2+1]);
+}
+
+void push(int ti, int tl, int tm, int tr) {
+  if (sety[ti] != -1) {
+    t[ti*2] = sety[ti] * FACTOR(tm - tl + 1);
+    lazy[ti*2] = 0; sety[ti*2] = sety[ti];
+    t[ti*2+1] = sety[ti] * FACTOR(tr - (tm+1) + 1);
+    lazy[ti*2+1] = 0; sety[ti*2+1] = sety[ti];
+    sety[ti] = -1;
+  }
+  t[ti*2] += lazy[ti] * FACTOR(tm - tl + 1);
+  lazy[ti*2] += lazy[ti];
+  t[ti*2+1] += lazy[ti] * FACTOR(tr - (tm+1) + 1);
+  lazy[ti*2+1] += lazy[ti];
+  lazy[ti] = 0;
+}
+
+void set_inclusive(int l, int r, int d,
+    int ti=1, int tl=1, int tr=N) {
+  if (l > r) { return; }
+  if (l == tl && tr == r) {
+    t[ti] = ll(d) * FACTOR(tr - tl + 1);
+    sety[ti] = d; lazy[ti] = 0; return; }
+  int tm = (tl + tr) / 2; push(ti, tl, tm, tr);
+  set_inclusive(l, min(r, tm), d, ti*2, tl, tm);
+  set_inclusive(max(l, tm+1), r, d, ti*2+1, tm+1, tr);
+  t[ti] = OP(t[ti*2], t[ti*2+1]);
+}
+
+void add_inclusive(int l, int r, int d,
+    int ti=1, int tl=1, int tr=N) {
+  if (l > r) { return; }
+  if (l == tl && tr == r) {
+    t[ti] += ll(d) * FACTOR(tr - tl + 1);
+    lazy[ti] += d; return; }
+  int tm = (tl + tr) / 2; push(ti, tl, tm, tr);
+  add_inclusive(l, min(r, tm), d, ti*2, tl, tm);
+  add_inclusive(max(l, tm+1), r, d, ti*2+1, tm+1, tr);
+  t[ti] = OP(t[ti*2], t[ti*2+1]);
+}
+
+ll op_inclusive(int l, int r,
+    int ti=1, int tl=1, int tr=N) {
+  if (l > r) { return NEUTRAL; }
+  if (l <= tl && tr <= r) { return t[ti]; }
+  int tm = (tl + tr) / 2; push(ti, tl, tm, tr);
+  return OP(op_inclusive(l, min(r, tm), ti*2, tl, tm),
+      op_inclusive(max(l, tm+1), r, ti*2+1, tm+1, tr));
+}
diff --git a/fontes/merge-sort.cpp b/fontes/merge-sort.h
similarity index 100%
rename from fontes/merge-sort.cpp
rename to fontes/merge-sort.h
diff --git a/fontes/mex.cpp b/fontes/mex.cpp
deleted file mode 100644
index 37a55370bd65aa99f30bffdf3eefc1bdcca8f8ee..0000000000000000000000000000000000000000
--- a/fontes/mex.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-int mex(set<int>& x) {
-  int m = 0;
-  for (auto &j : x) {
-    if (j > m) { return m; }
-    m++;
-  }
-  return m;
-}
diff --git a/fontes/mex.h b/fontes/mex.h
new file mode 100644
index 0000000000000000000000000000000000000000..081bf295071f00fab7c7b0303841559c2f17b1f1
--- /dev/null
+++ b/fontes/mex.h
@@ -0,0 +1,10 @@
+struct mex {
+  vector<bool> tomex; int gt = 0;
+  mex(int n) : tomex(n) {};
+  void insert_mex(int x) { tomex[x] = 1; gt = max(gt, x); }
+  int get_reset_mex() {
+    int m; for (m = 0; tomex[m]; m++);
+    fill(tomex.begin(), tomex.begin()+gt+1, 0);
+    return m;
+  }
+};
diff --git a/fontes/mexset.h b/fontes/mexset.h
new file mode 100644
index 0000000000000000000000000000000000000000..ca84990892fe97fdc0b2d1ac6437141a90ad2d06
--- /dev/null
+++ b/fontes/mexset.h
@@ -0,0 +1,11 @@
+struct mex {
+  set<int> tomex;
+  void insert_mex(int x) { tomex.insert(x); }
+  int get_reset_mex() {
+    int m = 0; for (auto &j : tomex) {
+      if (j > m) { tomex.clear(); return m; }
+      m++;
+    }
+    tomex.clear(); return m;
+  }
+};
diff --git a/fontes/min-queue-2.cpp b/fontes/min-queue-2.h
similarity index 100%
rename from fontes/min-queue-2.cpp
rename to fontes/min-queue-2.h
diff --git a/fontes/min-queue-3.cpp b/fontes/min-queue-3.h
similarity index 100%
rename from fontes/min-queue-3.cpp
rename to fontes/min-queue-3.h
diff --git a/fontes/min-queue.cpp b/fontes/min-queue.h
similarity index 100%
rename from fontes/min-queue.cpp
rename to fontes/min-queue.h
diff --git a/fontes/min-stack.cpp b/fontes/min-stack.h
similarity index 76%
rename from fontes/min-stack.cpp
rename to fontes/min-stack.h
index 3dcae22fa39312b660e5a09b7a883bec7c087cb1..904b5c2ac3f551dd409f8afbdd2ea052c0798c1f 100644
--- a/fontes/min-stack.cpp
+++ b/fontes/min-stack.h
@@ -1,7 +1,7 @@
 stack<pair<int, int>> st;
 
 void push_el(int x) {
-  int m = st.empty()?x:min(x, st.top().second);
+  int m = st.empty() ? x : min(x, st.top().second);
   st.push({x, m});
 }
 int pop_el() {
diff --git a/fontes/misere.cpp b/fontes/misere.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6298ac9f551a9ef7d938624315ae44a41cadb5b7
--- /dev/null
+++ b/fontes/misere.cpp
@@ -0,0 +1,18 @@
+#include <bits/stdc++.h>
+using namespace std;
+int main() {
+    cin.tie(0);
+    ios_base::sync_with_stdio(0);
+    int t; cin >> t;
+    while (t--) {
+        int n; cin >> n;
+        bool all_ones = true;
+        int res = 0;
+        for (int i = 0; i < n; i++) {
+            int x; cin >> x; res ^= x;
+            if (x != 1) { all_ones = false; }
+        }
+        if (all_ones) { res = n % 2 == 0; }
+        cout << (res != 0 ? "first" : "second") << "\n";
+    }
+}
diff --git a/fontes/modular-multiplicative-inverse.cpp b/fontes/modular-multiplicative-inverse.cpp
deleted file mode 100644
index fcfe8ad0747e02cc95e9ba59a04ec7265417722a..0000000000000000000000000000000000000000
--- a/fontes/modular-multiplicative-inverse.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-// faster O(lg min(x, m)), arbitrary m (coprime), x^-1 (mod m)
-int eucl_inv = (ext_gcd(x, m).x % m + m) % m;
-// slower O(lg P), P is prime, x^-1 = x^(P-2) (mod P)
-int fermat_inv = fast_pow(x, P - 2);
diff --git a/fontes/monotone.h b/fontes/monotone.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e9769bdfa489f8379075685ef8af0bb96cd6f47
--- /dev/null
+++ b/fontes/monotone.h
@@ -0,0 +1,18 @@
+vector<pt> convex_hull(vector<pt>& ps, bool col = false) {
+  int k = 0, n = ps.size(); vector<pt> ans (2*n);
+  sort(ps.begin(), ps.end(), [](pt a, pt b) {
+    return make_pair(a.px, a.py) < make_pair(b.px, b.py);
+  });
+  for (int i = 0; i < n; i++) {
+    while (k >= 2 && !ccw( /* lower hull */
+        ans[k-2], ans[k-1], ps[i], col)) { k--; }
+    ans[k++] = ps[i];
+  }
+  if (k == n) { ans.resize(n); return ans; }
+  for (int i = n-2, t = k+1; i >= 0; i--) {
+    while (k >= t && !ccw( /* upper hull */
+        ans[k-2], ans[k-1], ps[i], col)) { k--; }
+    ans[k++] = ps[i];
+  }
+  ans.resize(k-1); return ans;
+}
diff --git a/fontes/nge.cpp b/fontes/nge.cpp
deleted file mode 100644
index e4bac6a7d309f208677836db658b599b0441bc59..0000000000000000000000000000000000000000
--- a/fontes/nge.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-stack<int> pge;
-for (int i = n-1; i >= 0; i--) {
-    while (!pge.empty() && v[pge.top()] < v[i]) {
-        ans[pge.top()] = i; pge.pop();
-    }
-    pge.push(i);
-}
-
-stack<int> ple;
-for (int i = n-1; i >= 0; i--) {
-    while (!ple.empty() && v[ple.top()] > v[i]) {
-        ans[ple.top()] = i; ple.pop();
-    }
-    ple.push(i);
-}
-
-stack<int> nge;
-for (int i = 0; i < n; i++) {
-    while (!nge.empty() && v[nge.top()] < v[i]) {
-        ans[nge.top()] = i; nge.pop();
-    }
-    nge.push(i);
-}
-
-stack<int> nle;
-for (int i = 0; i < n; i++) {
-    while (!nle.empty() && v[nle.top()] > v[i]) {
-        ans[nle.top()] = i; nle.pop();
-    }
-    nle.push(i);
-}
diff --git a/fontes/nge.h b/fontes/nge.h
new file mode 100644
index 0000000000000000000000000000000000000000..f61e2aeb7a675927f278cf6a49681d8e4525c8f4
--- /dev/null
+++ b/fontes/nge.h
@@ -0,0 +1,7 @@
+stack<int> nge;
+for (int i = 0; i < n; i++) {
+  while (!nge.empty() && v[nge.top()] < v[i]) {
+    ans[nge.top()] = i; nge.pop();
+  }
+  nge.push(i);
+}
diff --git a/fontes/nim.cpp b/fontes/nim.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa6f8bbe35ad400abc60579a8baeb847ac35fed1
--- /dev/null
+++ b/fontes/nim.cpp
@@ -0,0 +1,17 @@
+#include <bits/stdc++.h>
+using namespace std;
+int main() {
+    int n; while (cin >> n) {
+        int g = 0;
+        vector<int> s (n);
+        for (int i = 0; i < n; i++) {
+            cin >> s[i]; g ^= s[i]; }
+        if (g == 0) { cout << "-1\n"; continue; }
+        int msb = (1<<__lg(g));
+        for (int i = 0; i < n; i++) if (s[i]&msb) {
+            int t = s[i]^g;
+            cout << s[i]-t << " " << i+1 << "\n";
+            break;
+        }
+    }
+}
diff --git a/fontes/nk-first-digits.cpp b/fontes/nk-first-last-digits.h
similarity index 55%
rename from fontes/nk-first-digits.cpp
rename to fontes/nk-first-last-digits.h
index 7c3613474c18540668fd66c92d253b3f89487bc9..6070efb3b2bdf20cb692182a403bb84e00a3bd2a 100644
--- a/fontes/nk-first-digits.cpp
+++ b/fontes/nk-first-last-digits.h
@@ -3,3 +3,8 @@ int first_d_digits(int n, int k, int d) {
   logged -= int(logged) - (d-1);
   return int(pow(10, logged));
 }
+
+int last_d_digits(int n, int k, int d) {
+  int p = 1; while (d--) { p *= 10; }
+  return fast_pow(n, k, p);
+}
diff --git a/fontes/nle.h b/fontes/nle.h
new file mode 100644
index 0000000000000000000000000000000000000000..a2c886358e341a85fd71ac267f25768a415ff214
--- /dev/null
+++ b/fontes/nle.h
@@ -0,0 +1,7 @@
+stack<int> nle;
+for (int i = 0; i < n; i++) {
+  while (!nle.empty() && v[nle.top()] > v[i]) {
+    ans[nle.top()] = i; nle.pop();
+  }
+  nle.push(i);
+}
diff --git a/fontes/node.h b/fontes/node.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0a514b51d46c86a869d830e6fb6ca7e4f4c05e4
--- /dev/null
+++ b/fontes/node.h
@@ -0,0 +1,9 @@
+struct node {
+  array<int, 9> data {{ 0 }};
+
+  node();
+  explicit node(int x);
+
+  node operator+(const node& a) { node n; return n; };
+  node operator+=(const int& a) { return *this; };
+};
diff --git a/fontes/noncoprimecrt.cpp b/fontes/noncoprimecrt.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ada3c3813001f80d52537185b86d3573bc30c7c
--- /dev/null
+++ b/fontes/noncoprimecrt.cpp
@@ -0,0 +1,26 @@
+#include <bits/stdc++.h>
+using namespace std;
+using ll = long long; using vll = vector<ll>;
+#include "extgcd.h"
+ll norm(ll a, ll b) { a %= b; return (a < 0) ? a + b : a; }
+pair<ll, ll> crt_single(ll a, ll n, ll b, ll m) {
+    ll x, y; ll g = extgcd(n, m, x, y);
+    if ((a - b) % g) { return {-1, -1}; }
+    ll lcm = (m/g) * n;
+    return {norm(a + n*(x*(b-a)/g % (m/g)), lcm), lcm};
+}
+ll crt /* O(t lg m1*..*mt) */ (vll a, vll m, int t) {
+    ll ans = a[0], lcm = m[0];
+    for (int i = 1; i < t; ++i) {
+        tie(ans, lcm) = crt_single(ans, lcm, a[i], m[i]);
+        if (ans == -1) { return -1; }
+    }
+    return ans;
+}
+int main() {
+    int t; while (cin >> t) {
+        vll a (t), m (t);
+        for (int i = 0; i < t; i++) { cin >> a[i] >> m[i]; }
+        cout << crt(a, m, t) << "\n";
+    }
+}
diff --git a/fontes/numbers.cpp b/fontes/numbers.h
similarity index 100%
rename from fontes/numbers.cpp
rename to fontes/numbers.h
diff --git a/fontes/pascal-triangle.cpp b/fontes/pascal-triangle.h
similarity index 100%
rename from fontes/pascal-triangle.cpp
rename to fontes/pascal-triangle.h
diff --git a/fontes/pge.h b/fontes/pge.h
new file mode 100644
index 0000000000000000000000000000000000000000..b9d1e97f2c324f5eb897d06764a64b9af98451e3
--- /dev/null
+++ b/fontes/pge.h
@@ -0,0 +1,7 @@
+stack<int> pge;
+for (int i = n-1; i >= 0; i--) {
+  while (!pge.empty() && v[pge.top()] < v[i]) {
+    ans[pge.top()] = i; pge.pop();
+  }
+  pge.push(i);
+}
diff --git a/fontes/ple.h b/fontes/ple.h
new file mode 100644
index 0000000000000000000000000000000000000000..97985c2655f621495a5441cfcdf02d093089a9c8
--- /dev/null
+++ b/fontes/ple.h
@@ -0,0 +1,7 @@
+stack<int> ple;
+for (int i = n-1; i >= 0; i--) {
+  while (!ple.empty() && v[ple.top()] > v[i]) {
+    ans[ple.top()] = i; ple.pop();
+  }
+  ple.push(i);
+}
diff --git a/fontes/point.h b/fontes/point.h
new file mode 100644
index 0000000000000000000000000000000000000000..822a380c0005b5d9c0fbe22559989377f623dc20
--- /dev/null
+++ b/fontes/point.h
@@ -0,0 +1,16 @@
+using pt = complex<double>;
+#define px real()
+#define py imag()
+double dot(pt a, pt b) { return (conj(a) * b).px; }
+double cross(pt a, pt b) { return (conj(a) * b).py; }
+pt vec(pt a, pt b) { return b - a; }
+int sgn(double v) { return (v > -EPS) - (v < EPS); }
+// -1 (cw), 0 (colinear), +1 (ccw)
+int seg_ornt(pt a, pt b, pt c) {
+    return sgn(cross(vec(a, b), vec(a, c))); }
+int ccw(pt a, pt b, pt c, bool col) {
+    int o = seg_ornt(a, b, c);
+    return (o == 1) || (o == 0 && col); }
+const double PI = acos(-1);
+double angle(pt a, pt b, pt c) {
+    return abs(remainder(arg(a-b) - arg(c-b), 2.0 * PI)); }
diff --git a/fontes/prefix-sum.cpp b/fontes/prefix-sum.cpp
deleted file mode 100644
index 8d9132230eacd5915ad32ee68856d74c02c0b303..0000000000000000000000000000000000000000
--- a/fontes/prefix-sum.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-vector<ll> prefix_sum(N+1, 0);
-vector<ll> origin(N); // origin has to be ll too
-
-void ps_build (int N) {
-  partial_sum(origin.begin(), origin.end(), prefix_sum.begin()+1);
-}
-
-// [a, b)
-ll ps_query (int a, int b) {
-  return prefix_sum[b] - prefix_sum[a];
-}
diff --git a/fontes/prefix-sum.h b/fontes/prefix-sum.h
new file mode 100644
index 0000000000000000000000000000000000000000..646f5144566cd520712eb409e1055f2785716ca3
--- /dev/null
+++ b/fontes/prefix-sum.h
@@ -0,0 +1,9 @@
+vector<ll> ps (N+1);
+
+void build(vector<ll>& origin) {
+  partial_sum(origin.begin(), origin.end(), ps.begin()+1);
+}
+
+ll sum_inclusive(int a, int b) {
+  return ps[b+1] - ps[a];
+}
diff --git a/fontes/prim.cpp b/fontes/prim.cpp
deleted file mode 100644
index 395f9cf22e1d8afd55901577e204a2a265e32e95..0000000000000000000000000000000000000000
--- a/fontes/prim.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-vvii graph (N), prim_tree (N);
-vector<bool> visited (N, false);
-vi min_parent (N, -1), min_weight (N, oo);
-
-int prim (int initial) {
-  int weight_sum = 0;
-  priority_queue<ii, vii, greater<ii>> Q;
-
-  Q.push(ii(0, initial));
-
-  while (!Q.empty()) {
-    int u = Q.top().uu;
-    int c = Q.top().cc;
-    Q.pop();
-
-    if (visited[u]) continue; visited[u] = true;
-    weight_sum += c;
-
-    if (min_parent[u] != -1) {
-      int v = min_parent[u];
-      int w = min_weight[u];
-      prim_tree[u].push_back(ii(v, w));
-      prim_tree[v].push_back(ii(u, w));
-    }
-
-    for (auto e : graph[u]) if (!visited[e.vv] && e.ww < min_weight[e.vv]) {
-      Q.push(ii(e.ww, e.vv));
-      min_weight[e.vv] = e.ww;
-      min_parent[e.vv] = u;
-    }
-  }
-
-  return weight_sum;
-}
diff --git a/fontes/prim.h b/fontes/prim.h
new file mode 100644
index 0000000000000000000000000000000000000000..666a8f4ebce89e0176e7c23765d01b415d0209fe
--- /dev/null
+++ b/fontes/prim.h
@@ -0,0 +1,26 @@
+vector<bool> vis (N);
+vector<int> par (N, -1);
+vector<ll> d (N, oo);
+vector<vector<ii>> pt (N);
+ll prim(int src) {
+  ll sum = 0;
+  priority_queue<ii, vector<ii>, greater<ii>> Q;
+  Q.push(ii(d[src] = 0, src));
+  while (!Q.empty()) {
+    auto [c, u] = Q.top(); Q.pop();
+    if (vis[u]) { continue; }
+    vis[u] = true;
+    if (par[u] != -1) {
+      int v = par[u]; ll w = d[u];
+      pt[u].push_back(ii(v, w));
+      pt[v].push_back(ii(u, w));
+    }
+    sum += c;
+    for (auto [v, w] : g[u])
+      if (!vis[v] && w < d[v]) {
+        Q.push(ii(d[v] = w, v));
+        par[v] = u;
+      }
+  }
+  return sum;
+}
diff --git a/fontes/rabinkarp.h b/fontes/rabinkarp.h
new file mode 100644
index 0000000000000000000000000000000000000000..c725ee9349429ec2f71850775d66c04c2184af83
--- /dev/null
+++ b/fontes/rabinkarp.h
@@ -0,0 +1,20 @@
+const int P = 31; const int M = 1e9 + 9;
+int search(string hay, string ne) {
+    int n = hay.size(), m = ne.size();
+    vector<ll> ps (max(n, m), 1);
+    for (int i = 1; i < max(n, m); i++)
+        ps[i] = (ps[i-1] * P) % M;
+    vector<ll> h (n+1, 0);
+    for (int i = 0; i < n; i++)
+        h[i+1] = (h[i] + (hay[i]-'a'+1) * ps[i]) % M;
+    ll hne = 0;
+    for (int i = 0; i < m; i++)
+        hne = (hne + (ne[i]-'a'+1) * ps[i]) % M;
+    int c = 0;
+    for (int i = 0; i < n - m + 1; i++)
+        if ((h[i+m] - h[i] + M) % M == hne * ps[i] % M) {
+            // match at i
+            c++;
+        }
+    return c;
+}
diff --git a/fontes/segment-tree.cpp b/fontes/segment-tree.cpp
deleted file mode 100644
index dabc300a9ad765e352b21c010354f472c1c7572b..0000000000000000000000000000000000000000
--- a/fontes/segment-tree.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-vector<T> stree(2*N), origin(N);
-
-#define LEFT 2*i
-#define RIGH 2*i+1
-#define M (ta+tb)/2
-
-void build /* O(n lg n) */ (int N) {
-  for (int i = 0; i < N; i++)
-    stree[N + i] = origin[i];
-  for (int i = N - 1; i > 0; i--)
-    stree[i] = OP(stree[LEFT], stree[RIGH]);
-}
-
-void update /* O(lg n) */ (int i, int d) {
-  stree[i += N] = d;
-  for (i /= 2; i > 0; i /= 2)
-    stree[i] = OP(stree[LEFT], stree[RIGH]);
-}
-
-T query_exclusive /* O(lg n) */ (int i, int j) {
-  auto left = NEUTRAL, right = NEUTRAL;
-  for (i += N, j += N; i < j; i /= 2, j /= 2) {
-    if (i & 1) left = OP(left, stree[i++]);
-    if (j & 1) right = OP(right, stree[--j]);
-  }
-  return OP(left, right);
-}
-
-struct node {
-  array<int, 9> data {{ 0 }};
-
-  node();
-  explicit node(int x);
-
-  node operator+(const node& a) { node n; return n; };
-  node operator+=(const int& a) { return *this; };
-};
diff --git a/fontes/stupid-hash.cpp b/fontes/simple-hash.h
similarity index 73%
rename from fontes/stupid-hash.cpp
rename to fontes/simple-hash.h
index 652c6bd277b4c7b8d6bbbe3ae80194e170f65ae6..15a59aa893a7d8bb24c345a035146d553023b193 100644
--- a/fontes/stupid-hash.cpp
+++ b/fontes/simple-hash.h
@@ -1,21 +1,21 @@
 const int HS = 10000;
-vector<ll> key (HS), value (HS), ts (HS);
-
 int cts = 0;
+vector<ll> key (HS), value (HS), ts (HS);
 
 void hash_put(ll k, ll v) {
   ll pos = k % HS;
-  while (ts[pos] == cts)
+  while (ts[pos] == cts) {
     pos++; pos %= HS;
+  }
   ts[pos] = cts;
-  key[pos] = k;
-  value[pos] = v;
+  key[pos] = k; value[pos] = v;
 }
 
 ll hash_get(ll k) {
   ll pos = k % HS;
-  while (ts[pos] == cts && key[pos] != k)
+  while (ts[pos] == cts && key[pos] != k) {
     pos++; pos %= HS;
+  }
   if (ts[pos] == cts && key[pos] == k)
     return value[pos];
   return -1;
diff --git a/fontes/square-root-tree-decomposition.cpp b/fontes/square-root-tree-decomposition.cpp
deleted file mode 100644
index 8b8fa9e2578bad7c6188cf6bd80c419ec85be5f8..0000000000000000000000000000000000000000
--- a/fontes/square-root-tree-decomposition.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-int B;
-
-vvil graph = vvil(MAX_N);
-
-vi heights (MAX_N);
-vi parents (MAX_N);
-vll costs (MAX_N);
-vll upto_block_costs (MAX_N);
-vi block_parents (MAX_N);
-
-void std_decompose (int u, int parent, int cost) {
-  parents[u] = parent;
-  costs[u] = cost;
-
-  if (parent != -1) {
-    heights[u] = heights[parent] + 1;
-    block_parents[u] = heights[u] % B ? block_parents[parent] : parent;
-    upto_block_costs[u] = (heights[u] % B ? upto_block_costs[parent] : 0) + cost;
-  }
-
-  for (auto e : graph[u]) {
-    int v, c;
-    tie(v, c) = e;
-    if (v != parent) {
-      std_decompose(v, u, c);
-    }
-  }
-}
-
-ll std_query (int a, int b) {
-  ll result = 0;
-
-  while (heights[a]/B > heights[b]/B) { result += upto_block_costs[a]; a = block_parents[a]; }
-  while (heights[b]/B > heights[a]/B) { result += upto_block_costs[b]; b = block_parents[b]; }
-  while (heights[a] > heights[b]) { result += costs[a]; a = parents[a]; }
-  while (heights[b] > heights[a]) { result += costs[b]; b = parents[b]; }
-
-  while (a != b) {
-    result += costs[a]; a = parents[a];
-    result += costs[b]; b = parents[b];
-  }
-
-  return result;
-}
diff --git a/fontes/stable-matching.cpp b/fontes/stable-matching.cpp
deleted file mode 100644
index e71e6f581f97e57c7f4d4d1bbb60dabf3cc7d852..0000000000000000000000000000000000000000
--- a/fontes/stable-matching.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Gale-Shapley
-// O(n^2)
-
-vector<vector<int>> pref_m (n, vector<int>(n)); // [m][j] = w
-vector<vector<int>> pref_w_idx (n, vector<int>(n+1)); // [w][m] = j
-
-// m
-vector<bool> single (n, true);
-vector<int> match (n, -1);
-// w
-vector<int> watch (n, n);
-
-vector<ii> galeshapley(int n) {
-  // sentinel
-  for (int w = 0; w < n; w++) { pref_w_idx[w][n] = n; }
-
-  bool done = false;
-  while (!done) {
-    done = true;
-    for (int m = 0; m < n; m++) if (single[m]) {
-      done = false;
-      match[m] += 1;
-      int w = pref_m[m][match[m]];
-      if (pref_w_idx[w][m] < pref_w_idx[w][watch[w]]) {
-        single[watch[w]] = true;
-        watch[w] = m;
-        single[m] = false;
-      }
-    }
-  }
-
-  vector<ii> ans;
-  for (int m = 0; m < n; m++) {
-    ans.push_back(ii(m, pref_m[m][match[m]]));
-  }
-  return ans;
-}
diff --git a/fontes/stable-matching.h b/fontes/stable-matching.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb2b5924a193d7fa5b7550eab899e3513ef756c4
--- /dev/null
+++ b/fontes/stable-matching.h
@@ -0,0 +1,30 @@
+vector<vector<int>> pm (N, vector<int>(N)); // [m][j] = w
+vector<vector<int>> pwix (N, vector<int>(N+1)); // [w][m] = j
+
+vector<bool> single (N, true);
+vector<int> match (N, -1), watch (N, N);
+
+vector<ii> galeshapley(int n) {
+  // sentinel
+  for (int w = 0; w < n; w++) { pwix[w][n] = n; }
+
+  bool done = false;
+  while (!done) {
+    done = true;
+    for (int m = 0; m < n; m++) if (single[m]) {
+      done = false;
+      match[m] += 1;
+      int w = pm[m][match[m]];
+      if (pwix[w][m] < pwix[w][watch[w]]) {
+        single[watch[w]] = true;
+        watch[w] = m;
+        single[m] = false;
+      }
+    }
+  }
+
+  vector<ii> ans;
+  for (int m = 0; m < n; m++)
+    ans.push_back(ii(m, pm[m][match[m]]));
+  return ans;
+}
diff --git a/fontes/stair.cpp b/fontes/stair.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ff33125cfe15916497281e1a0b46c32cf1442a2
--- /dev/null
+++ b/fontes/stair.cpp
@@ -0,0 +1,14 @@
+#include <bits/stdc++.h>
+using namespace std;
+int main() {
+  int t; cin >> t;
+  while (t--) {
+    int n; cin >> n;
+    int ans = 0;
+    for (int i = 0; i < n; i++) {
+      int p; cin >> p;
+      if (i % 2) { ans ^= p; }
+    }
+    cout << (ans == 0 ? "second" : "first") << "\n";
+  }
+}
diff --git a/fontes/stdt.h b/fontes/stdt.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb51d9c81d66c3ea8fac7679f8b9e213765bba81
--- /dev/null
+++ b/fontes/stdt.h
@@ -0,0 +1,27 @@
+vector<int> depth (N);
+vector<int> up (N); vector<int> weiop (N);
+vector<int> bup (N); vector<int> bweiop (N);
+
+void stdt_decompose(int u, int p, int w) {
+    up[u] = p; weiop[u] = w;
+    depth[u] = depth[p] + 1;
+    bup[u] = depth[u] % B ? bup[p] : p;
+    bweiop[u] = OP(depth[u] % B ? bweiop[p] : NEUTRAL, w);
+    for (auto [v, w] : g[u]) if (v != p)
+        stdt_decompose(v, u, w);
+}
+
+int stdt_op(int a, int b) {
+    int ans = NEUTRAL;
+    if (!(depth[a]/B > depth[b]/B)) { swap(a, b); }
+    while (depth[a]/B > depth[b]/B) {
+        ans = OP(ans, bweiop[a]); a = bup[a]; }
+    if (!(depth[a] > depth[b])) { swap(a, b); }
+    while (depth[a] > depth[b]) {
+        ans = OP(ans, weiop[a]); a = up[a]; }
+    while (a != b) {
+        ans = OP(ans, OP(weiop[a], weiop[b]));
+        a = up[a]; b = up[b];
+    }
+    return ans;
+}
diff --git a/fontes/stdtlca.h b/fontes/stdtlca.h
new file mode 100644
index 0000000000000000000000000000000000000000..41da9b4733c3612433535b3f284b0acc0476d7fb
--- /dev/null
+++ b/fontes/stdtlca.h
@@ -0,0 +1,8 @@
+int std_lca(int a, int b) {
+    if (!(depth[a]/B > depth[b]/B)) { swap(a, b); }
+    while (depth[a]/B > depth[b]/B) { a = bup[a]; }
+    if (!(depth[a] > depth[b])) { swap(a, b); }
+    while (depth[a] > depth[b]) { a = up[a]; }
+    while (a != b) { a = up[a]; b = up[b]; }
+    return a;
+}
diff --git a/fontes/stdtop.h b/fontes/stdtop.h
new file mode 100644
index 0000000000000000000000000000000000000000..71cfbf9ff1c420448f7bb3770facae58dec2d4da
--- /dev/null
+++ b/fontes/stdtop.h
@@ -0,0 +1,14 @@
+int stdt_op(int a, int b) {
+    int ans = NEUTRAL;
+    if (!(depth[a]/B > depth[b]/B)) { swap(a, b); }
+    while (depth[a]/B > depth[b]/B) {
+        ans = OP(ans, bweiop[a]); a = bup[a]; }
+    if (!(depth[a] > depth[b])) { swap(a, b); }
+    while (depth[a] > depth[b]) {
+        ans = OP(ans, weiop[a]); a = up[a]; }
+    while (a != b) {
+        ans = OP(ans, OP(weiop[a], weiop[b]));
+        a = up[a]; b = up[b];
+    }
+    return ans;
+}
diff --git a/fontes/stit.h b/fontes/stit.h
new file mode 100644
index 0000000000000000000000000000000000000000..8ce8562d549e300372cc5b399c666da5bdb0b9a9
--- /dev/null
+++ b/fontes/stit.h
@@ -0,0 +1,24 @@
+vector<int> t (2*N);
+
+void build(vector<int>& src) {
+  for (int i = 1; i < src.size(); i++)
+    t[N+i] = src[i];
+  for (int i = N-1; i > 0; i--)
+    t[i] = OP(t[2*i], t[2*i+1]);
+}
+
+int op_inclusive(int l, int r) {
+  r++;
+  int left = NEUTRAL, right = NEUTRAL;
+  for (l += N, r += N; l < r; l /= 2, r /= 2) {
+    if (l & 1) left = OP(left, t[l++]);
+    if (r & 1) right = OP(right, t[--r]);
+  }
+  return OP(left, right);
+}
+
+void set_value(int i, int v) {
+  t[i += N] = v;
+  for (i /= 2; i > 0; i /= 2)
+    t[i] = OP(t[i*2], t[i*2+1]);
+}
diff --git a/fontes/stoer-wagner.cpp b/fontes/stoer-wagner.h
similarity index 100%
rename from fontes/stoer-wagner.cpp
rename to fontes/stoer-wagner.h
diff --git a/fontes/strec.h b/fontes/strec.h
new file mode 100644
index 0000000000000000000000000000000000000000..10916c2e8681ff14529e904752ff0d0320cde8c3
--- /dev/null
+++ b/fontes/strec.h
@@ -0,0 +1,33 @@
+vector<ll> t (4*N);
+
+void build(vector<ll>& src,
+    int ti=1, int tl=1, int tr=N) {
+  if (tl == tr) {
+    if (tl < src.size()) { t[ti] = src[tl]; }
+    return;
+  }
+  int tm = (tl + tr) / 2;
+  build(src, ti*2, tl, tm);
+  build(src, ti*2+1, tm+1, tr);
+  t[ti] = OP(t[ti*2], t[ti*2+1]);
+}
+
+ll op_inclusive(int l, int r,
+    int ti=1, int tl=1, int tr=N) {
+  if (l > r) { return NEUTRAL; }
+  if (l == tl && r == tr) { return t[ti]; }
+  int tm = (tl + tr) / 2;
+  return OP(op_inclusive(l, min(r, tm), ti*2, tl, tm),
+      op_inclusive(max(l, tm+1), r, ti*2+1, tm+1, tr));
+}
+
+void set_value(int i, ll v,
+    int ti=1, int tl=1, int tr=N) {
+  if (tl == tr) { t[ti] = v; return; }
+  int tm = (tl + tr) / 2;
+  if (i <= tm)
+    set_value(i, v, ti*2, tl, tm);
+  else
+    set_value(i, v, ti*2+1, tm+1, tr);
+  t[ti] = OP(t[ti*2], t[ti*2+1]);
+}
diff --git a/fontes/suffix-tree.cpp b/fontes/suffix-tree.cpp
deleted file mode 100644
index 33ab59b96bad754f766064628cde3d3f23faf19e..0000000000000000000000000000000000000000
--- a/fontes/suffix-tree.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-struct suffix_tree {
-  vector<vector<int>> nxt;
-  vector<int> l, r;
-  vector<int> parent;
-  vector<int> suf;
-
-  suffix_tree() : nxt(MAXN, vector<int>(5)), l(MAXN), r(MAXN),
-  parent(MAXN), suf(MAXN) {}
-
-  int len(int i) { return r[i] - l[i] + 1; }
-
-  int at(string& s, int i, int j) { return id(s[l[i] + j]); }
-
-  int cur = 1;
-
-  int new_node (int a, int b, int p) {
-    l[cur] = a, r[cur] = b;
-    parent[cur] = p;
-    return cur++;
-  }
-
-  void build (string s) {
-    s += '$';
-    int root = new_node(0, -1, 0);
-    int u = root, i = 0, ui = 0, ns = 0;
-    for (int j = 0; j < s.size(); j++)
-      for (; i <= j; i++) {
-        if (ui == len(u) && nxt[u][id(s[j])]) {
-          u = nxt[u][id(s[j])];
-          ui = 0;
-        }
-        if (ui < len(u) && at(s, u, ui) == id(s[j])) {
-          ui++; break;
-        }
-        if (ui == len(u)) {
-          nxt[u][id(s[j])] = new_node(j, s.size()-1, u);
-          if (u != root) {
-            u = suf[u];
-            ui = len(u);
-          }
-        } else {
-          int mi = new_node(l[u], l[u] + ui - 1, parent[u]);
-          nxt[parent[u]][at(s, mi, 0)] = mi;
-          nxt[mi][at(s, u, ui)] = u;
-          parent[u] = mi;
-          l[u] += ui;
-          nxt[mi][id(s[j])] = new_node(j, s.size()-1, mi);
-          if (ns) { suf[ns] = mi; }
-          u = parent[mi];
-          int g;
-          if (u != root) {
-            u = suf[u];
-            g = j - ui;
-          } else {
-            g = i + 1;
-          }
-          while (g < j && g + len(nxt[u][id(s[g])]) <= j) {
-            u = nxt[u][id(s[g])];
-            g += len(u);
-          }
-          if (g == j) {
-            ns = 0;
-            suf[mi] = u;
-            ui = len(u);
-          } else {
-            ns = mi;
-            u = nxt[u][id(s[g])];
-            ui = j - g;
-          }
-        }
-      }
-  }
-};
diff --git a/fontes/suffix-tree.h b/fontes/suffix-tree.h
new file mode 100644
index 0000000000000000000000000000000000000000..fcfcbbe4677fa27d05db2cb47c35e8374c5dc415
--- /dev/null
+++ b/fontes/suffix-tree.h
@@ -0,0 +1,72 @@
+struct suffix_tree {
+  vector<vector<int>> nxt;
+  vector<int> l, r;
+  vector<int> parent;
+  vector<int> suf;
+
+  suffix_tree() : nxt(N, vector<int>(5)), l(N), r(N),
+  parent(N), suf(N) {}
+
+  int len(int i) { return r[i] - l[i] + 1; }
+
+  int at(string& s, int i, int j) { return id(s[l[i] + j]); }
+
+  int cur = 1;
+
+  int new_node(int a, int b, int p) {
+    l[cur] = a, r[cur] = b;
+    parent[cur] = p;
+    return cur++;
+  }
+
+  void build(string s) {
+    s += '$';
+    int root = new_node(0, -1, 0);
+    int u = root, i = 0, ui = 0, ns = 0;
+    for (int j = 0; j < s.size(); j++) for (; i <= j; i++) {
+      if (ui == len(u) && nxt[u][id(s[j])]) {
+        u = nxt[u][id(s[j])];
+        ui = 0;
+      }
+      if (ui < len(u) && at(s, u, ui) == id(s[j])) {
+        ui++; break;
+      }
+      if (ui == len(u)) {
+        nxt[u][id(s[j])] = new_node(j, s.size()-1, u);
+        if (u != root) {
+          u = suf[u];
+          ui = len(u);
+        }
+      } else {
+        int mi = new_node(l[u], l[u] + ui - 1, parent[u]);
+        nxt[parent[u]][at(s, mi, 0)] = mi;
+        nxt[mi][at(s, u, ui)] = u;
+        parent[u] = mi;
+        l[u] += ui;
+        nxt[mi][id(s[j])] = new_node(j, s.size()-1, mi);
+        if (ns) { suf[ns] = mi; }
+        u = parent[mi];
+        int g;
+        if (u != root) {
+          u = suf[u];
+          g = j - ui;
+        } else {
+          g = i + 1;
+        }
+        while (g < j && g + len(nxt[u][id(s[g])]) <= j) {
+          u = nxt[u][id(s[g])];
+          g += len(u);
+        }
+        if (g == j) {
+          ns = 0;
+          suf[mi] = u;
+          ui = len(u);
+        } else {
+          ns = mi;
+          u = nxt[u][id(s[g])];
+          ui = j - g;
+        }
+      }
+    }
+  }
+};
diff --git a/fontes/tarjan.h b/fontes/tarjan.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a16e74bc7087a7d65f650c7a0b8f6db6034eddb
--- /dev/null
+++ b/fontes/tarjan.h
@@ -0,0 +1,20 @@
+vector<int> tin (N, -1), lowlnk (N, -1), rep (N);
+stack<int> st;
+void dfs_tarjan(int u) {
+    if (tin[u] != -1) { return; }
+    lowlnk[u] = tin[u] = vis[u] = cts++;
+    st.push(u);
+    for (int v : g[u]) {
+        dfs_tarjan(v);
+        if (vis[v]) lowlnk[u] = min(lowlnk[u], lowlnk[v]);
+    }
+    if (lowlnk[u] == tin[u]) {
+        int v; do {
+            v = st.top(); st.pop(); vis[v] = 0;
+            rep[v] = u;
+        } while (u != v);
+    }
+}
+void tarjan(int n) {
+    for (int u = 0; u < n; u++) { dfs_tarjan(u); }
+}
diff --git a/fontes/topo.h b/fontes/topo.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3b991201700a343716b01f280bd29d224ddca2b
--- /dev/null
+++ b/fontes/topo.h
@@ -0,0 +1,17 @@
+vector<bool> vis (N); stack<int> st;
+void dfs_topo(int u) {
+    if (vis[u]) { return; }
+    vis[u] = 1;
+    for (int v : g[u]) { dfs_topo(v); }
+    st.push(u);
+}
+vector<int> toposort(int n) {
+  fill(visited.begin(), visited.begin() + n, false);
+    vector<int> topo;
+    for (int u = 0; u < n; u++) { dfs_topo(u); }
+    while (!st.empty()) {
+        int v = st.top(); st.pop();
+        topo.push_back(v);
+    }
+    return topo;
+}
diff --git a/fontes/topological-sort.cpp b/fontes/topological-sort.cpp
deleted file mode 100644
index 0fd1a4d8189373b58f732bfa8e2e9b014e8772ba..0000000000000000000000000000000000000000
--- a/fontes/topological-sort.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-stack<int> S;
-vector<bool> visited (n);
-
-void dfs(int u) {
-    if (visited[u]) return;
-    visited[u] = true;
-    for (int v : G[u]) { dfs(v); }
-    S.push(u);
-}
-
-void topo_sort(int n) {
-  fill(visited.begin(), visited.begin() + n, false);
-  for (int u = 0; u < n; u++) { dfs(u); }
-  while (!S.empty()) {
-    int v = S.top(); S.pop();
-  }
-}
diff --git a/fontes/trie.h b/fontes/trie.h
new file mode 100644
index 0000000000000000000000000000000000000000..5fd31f9e27d3ca5fe4700f0c2880f6399e48fc9c
--- /dev/null
+++ b/fontes/trie.h
@@ -0,0 +1,18 @@
+struct trie {
+  vector<int> nxt; int cnt; bool leaf;
+  trie() : nxt (S, -1), cnt (0), leaf (false) {}
+};
+vector<trie> t (1);
+void ins(string ne) {
+  int u = 0;
+  for (char c : ne) {
+    int ch = to_i(c);
+    if (t[u].nxt[ch] == -1) {
+      t[u].nxt[ch] = t.size();
+      trie n; t.push_back(n);
+    }
+    u = t[u].nxt[ch];
+    t[u].cnt++;
+  }
+  t[u].leaf = true;
+}
diff --git a/testes/convex-hull.cpp b/testes/convex-hull.cpp
deleted file mode 100644
index a3b322609163e0c1e11a18c697cd5f7e38fe10c3..0000000000000000000000000000000000000000
--- a/testes/convex-hull.cpp
+++ /dev/null
@@ -1,265 +0,0 @@
-#include <bits/stdc++.h>
-using namespace std; using ll = long long;
-
-#define $(X) {if (DEBUG) { \
-  cerr << __LINE__ << ":"; {x} cerr << endl;}}
-#define _(X) {cerr << #X << " = " << X << " ";}
-
-#define all(x) x.begin(), x.end()
-#define px real()
-#define py imag()
-#define mp make_pair
-typedef complex<double> pt;
-typedef vector<pt> vpt;
-
-int sgn (double v) { return (v > 0) - (v < 0); }
-// -1 (cw), 0 (colinear), +1 (ccw)
-int seg_ornt (pt a, pt b, pt c) {
-  return sgn(cross(vec(a, b), vec(a, c)));
-}
-
-// doesn't include collinear points (<= -> < to include)
-vpt convex_hull_ccw /* O(n lg n) */ (vpt& ps) {
-  int k = 0, n = ps.size();
-  vpt result (n * 2);
-
-  sort(all(ps), [](pt a, pt b) {
-    return mp(a.px, a.py) < mp(b.px, b.py);
-  });
-
-  for (int i = 0; i < n; i++) {
-    while (k >= 2 && seg_ornt( /* lower hull */
-        result[k-2], result[k-1], ps[i]) <= 0) k--;
-    result[k++] = ps[i];
-  }
-
-  for (int i = n - 2, t = k + 1; i >= 0; i--) {
-    while (k >= t && seg_ornt( /* upper hull */
-        result[k-2], result[k-1], ps[i]) <= 0) k--;
-    result[k++] = ps[i];
-  }
-
-  result.resize(k - 1);
-  return result;
-}
-vpt convex_hull_cw /* O(n lg n) */ (vpt& ps) {
-  int k = 0, n = ps.size();
-  vpt result (n * 2);
-
-  sort(all(ps), [](pt a, pt b) {
-    return mp(a.px, a.py) < mp(b.px, b.py);
-  });
-
-  for (int i = 0; i < n; i++) {
-    while (k >= 2 && seg_ornt( /* lower hull */
-        result[k-2], result[k-1], ps[i]) >= 0) k--;
-    result[k++] = ps[i];
-  }
-
-  for (int i = n - 2, t = k + 1; i >= 0; i--) {
-    while (k >= t && seg_ornt( /* upper hull */
-        result[k-2], result[k-1], ps[i]) >= 0) k--;
-    result[k++] = ps[i];
-  }
-
-  result.resize(k - 1);
-  return result;
-}
-vpt convex_hull_ccw_colinear /* O(n lg n) */ (vpt& ps) {
-  int k = 0, n = ps.size();
-  vpt result (n * 2);
-
-  sort(all(ps), [](pt a, pt b) {
-    return mp(a.px, a.py) < mp(b.px, b.py);
-  });
-
-  for (int i = 0; i < n; i++) {
-    while (k >= 2 && seg_ornt( /* lower hull */
-        result[k-2], result[k-1], ps[i]) < 0) k--;
-    result[k++] = ps[i];
-  }
-
-  for (int i = n - 2, t = k + 1; i >= 0; i--) {
-    while (k >= t && seg_ornt( /* upper hull */
-        result[k-2], result[k-1], ps[i]) < 0) k--;
-    result[k++] = ps[i];
-  }
-
-  result.resize(k - 1);
-  return result;
-}
-
-vpt convex_hull_cw_colinear /* O(n lg n) */ (vpt& ps) {
-  int k = 0, n = ps.size();
-  vpt result (n * 2);
-
-  sort(all(ps), [](pt a, pt b) {
-    return mp(a.px, a.py) < mp(b.px, b.py);
-  });
-
-  for (int i = 0; i < n; i++) {
-    while (k >= 2 && seg_ornt( /* lower hull */
-        result[k-2], result[k-1], ps[i]) > 0) k--;
-    result[k++] = ps[i];
-  }
-
-  for (int i = n - 2, t = k + 1; i >= 0; i--) {
-    while (k >= t && seg_ornt( /* upper hull */
-        result[k-2], result[k-1], ps[i]) > 0) k--;
-    result[k++] = ps[i];
-  }
-
-  result.resize(k - 1);
-  return result;
-}
-
-int main() {
-  ios::sync_with_stdio(0); cin.tie(0);
-  vpt convex;
-
-  // 1 |*   *
-  // 0 |* * *
-  // y +-----
-  //  x 0 1 2
-  vpt points { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 } };
-
-  // 1 |3   2
-  // 0 |0 * 1
-  // y +-----
-  //  x 0 1 2
-  convex = convex_hull_ccw(points);
-  assert(convex.size() == 4);
-  assert(convex[0] == pt(0, 0));
-  assert(convex[1] == pt(2, 0));
-  assert(convex[2] == pt(2, 1));
-  assert(convex[3] == pt(0, 1));
-
-  // 1 |1   2
-  // 0 |0 * 3
-  // y +-----
-  //  x 0 1 2
-  convex = convex_hull_cw(points);
-  assert(convex.size() == 4);
-  assert(convex[0] == pt(0, 0));
-  assert(convex[1] == pt(0, 1));
-  assert(convex[2] == pt(2, 1));
-  assert(convex[3] == pt(2, 0));
-
-  // 1 |4   3
-  // 0 |0 1 2
-  // y +-----
-  //  x 0 1 2
-  convex = convex_hull_ccw_colinear(points);
-  assert(convex.size() == 5);
-  assert(convex[0] == pt(0, 0));
-  assert(convex[1] == pt(1, 0));
-  assert(convex[2] == pt(2, 0));
-  assert(convex[3] == pt(2, 1));
-  assert(convex[4] == pt(0, 1));
-
-  // 1 |1   2
-  // 0 |0 4 3
-  // y +-----
-  //  x 0 1 2
-  convex = convex_hull_cw_colinear(points);
-  assert(convex.size() == 5);
-  assert(convex[0] == pt(0, 0));
-  assert(convex[1] == pt(0, 1));
-  assert(convex[2] == pt(2, 1));
-  assert(convex[3] == pt(2, 0));
-  assert(convex[4] == pt(1, 0));
-
-  vpt ten_by_ten_grid;
-
-  // 9 |* * * * * * * * * *
-  // 8 |* * * * * * * * * *
-  // 7 |* * * * * * * * * *
-  // 6 |* * * * * * * * * *
-  // 5 |* * * * * * * * * *
-  // 4 |* * * * * * * * * *
-  // 3 |* * * * * * * * * *
-  // 2 |* * * * * * * * * *
-  // 1 |* * * * * * * * * *
-  // 0 |* * * * * * * * * *
-  // y +-------------------
-  //  x 0 1 2 3 4 5 6 7 8 9
-  for (int i = 0; i < 100; i++) {
-    ten_by_ten_grid.push_back(pt(i / 10, i % 10));
-  }
-
-  // 9 |3 * * * * * * * * 2
-  // 8 |* * * * * * * * * *
-  // 7 |* * * * * * * * * *
-  // 6 |* * * * * * * * * *
-  // 5 |* * * * * * * * * *
-  // 4 |* * * * * * * * * *
-  // 3 |* * * * * * * * * *
-  // 2 |* * * * * * * * * *
-  // 1 |* * * * * * * * * *
-  // 0 |0 * * * * * * * * 1
-  // y +-------------------
-  //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_ccw(ten_by_ten_grid);
-  assert(convex.size() == 4);
-  assert(convex[0] == pt(0., 0.));
-  assert(convex[1] == pt(9., 0.));
-  assert(convex[2] == pt(9., 9.));
-  assert(convex[3] == pt(0., 9.));
-
-  // 9 |1 * * * * * * * * 2
-  // 8 |* * * * * * * * * *
-  // 7 |* * * * * * * * * *
-  // 6 |* * * * * * * * * *
-  // 5 |* * * * * * * * * *
-  // 4 |* * * * * * * * * *
-  // 3 |* * * * * * * * * *
-  // 2 |* * * * * * * * * *
-  // 1 |* * * * * * * * * *
-  // 0 |0 * * * * * * * * 3
-  // y +-------------------
-  //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_cw(ten_by_ten_grid);
-  assert(convex.size() == 4);
-  assert(convex[0] == pt(0., 0.));
-  assert(convex[1] == pt(0., 9.));
-  assert(convex[2] == pt(9., 9.));
-  assert(convex[3] == pt(9., 0.));
-
-  // 9 |R Q P O N M L K J I
-  // 8 |S * * * * * * * * H
-  // 7 |T * * * * * * * * G
-  // 6 |U * * * * * * * * F
-  // 5 |V * * * * * * * * E
-  // 4 |W * * * * * * * * D
-  // 3 |X * * * * * * * * C
-  // 2 |Y * * * * * * * * B
-  // 1 |Z * * * * * * * * A
-  // 0 |0 1 2 3 4 5 6 7 8 9
-  // y +-------------------
-  //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_ccw_colinear(ten_by_ten_grid);
-  assert(convex.size() == 36);
-  for (int i = 0; i < 9; i++) assert(convex[i+9*0] == pt(i-0, 0.));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*1] == pt(9., i-0));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*2] == pt(9-i, 9.));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*3] == pt(0., 9-i));
-
-  // 9 |9 A B C D E F G H I
-  // 8 |8 * * * * * * * * J
-  // 7 |7 * * * * * * * * K
-  // 6 |6 * * * * * * * * L
-  // 5 |5 * * * * * * * * M
-  // 4 |4 * * * * * * * * N
-  // 3 |3 * * * * * * * * O
-  // 2 |2 * * * * * * * * P
-  // 1 |1 * * * * * * * * Q
-  // 0 |0 Z Y X W V U T S R
-  // y +-------------------
-  //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_cw_colinear(ten_by_ten_grid);
-  assert(convex.size() == 36);
-  for (int i = 0; i < 9; i++) assert(convex[i+9*0] == pt(0., i-0));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*1] == pt(i-0, 9.));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*2] == pt(9., 9-i));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*3] == pt(9-i, 0.));
-}
diff --git a/testes/fenwick-2d-tree.cpp b/testes/fenwick-2d-tree.cpp
index 8b3d46f4ed581648f3b529006f72a1e3cd559585..eaedb2fcc256e54882ed0a80b356254bf2733780 100644
--- a/testes/fenwick-2d-tree.cpp
+++ b/testes/fenwick-2d-tree.cpp
@@ -1,51 +1,23 @@
 #include <bits/stdc++.h>
 using namespace std; using ll = long long;
 
-#define $(X) {if (DEBUG) { \
-  cerr << __LINE__ << ":"; {x} cerr << endl;}}
-#define _(X) {cerr << #X << " = " << X << " ";}
+const int N = 1e3 + 3;
+const int M = 1e3 + 3;
 
-const int ftN = 1e3 + 3;
-const int ftM = 1e3 + 3;
-
-typedef vector<int> vi;
-typedef vector<vector<int>> vvi;
-
-vvi ftree(ftN, vi(ftM, 0)); // 1-indexed
-
-void ft_add /* O(lg^2 n) */ (int x,int y,int d) {
-  for (; x < ftN; x += x & -x)
-  for (int j = y; j < ftM; j += j & -j)
-    ftree[x][j] += d;
-}
-
-int ft_rsq_upto /* O(lg^2 n) */ (int x, int y) {
-  int sum = 0;
-  for (; x > 0; x -= x & -x)
-  for (int j = y; j > 0; j -= j & -j)
-    sum += ftree[x][j];
-  return sum;
-}
-
-int ft_rsq /* O(lg^2 n) */ (
-    int x1, int y1, int x2, int y2) {
-  return ft_rsq_upto(x2, y2)
-    - ft_rsq_upto(x2, y1 - 1)
-    - ft_rsq_upto(x1 - 1, y2)
-    + ft_rsq_upto(x1 - 1, y1 - 1);
-}
+#include "../fontes/fenwick-2d-tree.h"
 
 int main() {
   ios::sync_with_stdio(0); cin.tie(0);
-  ft_add(1, 1, 1);
-  ft_add(1, 2, 3);
-  ft_add(1, 3, 9);
-  ft_add(2, 1, 5);
-  ft_add(2, 2, 5);
-  ft_add(2, 3, 8);
 
-  assert(ft_rsq(1, 1, 1, 1) == 1);
-  assert(ft_rsq(2, 2, 2, 2) == 5);
-  assert(ft_rsq(1, 1, 2, 2) == 1+3+5+5);
-  assert(ft_rsq(1, 1, 2, 3) == 1+3+9+5+5+8);
+  add(1, 1, 1);
+  add(1, 2, 3);
+  add(1, 3, 9);
+  add(2, 1, 5);
+  add(2, 2, 5);
+  add(2, 3, 8);
+
+  assert(sum_inclusive(1, 1, 1, 1) == 1);
+  assert(sum_inclusive(2, 2, 2, 2) == 5);
+  assert(sum_inclusive(1, 1, 2, 2) == 1+3+5+5);
+  assert(sum_inclusive(1, 1, 2, 3) == 1+3+9+5+5+8);
 }
diff --git a/testes/fenwick-2d-tree.gen b/testes/fenwick-2d-tree.gen
deleted file mode 100755
index 78a4fe46051ff8bd2fbe2cae1b89ceed53aeb275..0000000000000000000000000000000000000000
--- a/testes/fenwick-2d-tree.gen
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-ed -s testes/fenwick-2d-tree.cpp <<'EOF'
-# toggle debug helper
-H
-# delete all lines
-,d
-# add template
-r fontes/template.cpp
-# find main
-/int main() {/
-# add info before main
-i
-const int ftN = 1e3 + 3;
-const int ftM = 1e3 + 3;
-
-typedef vector<int> vi;
-typedef vector<vector<int>> vvi;
-
-.
-# add fenwick-2d-tree right before that space
-.r fontes/fenwick-2d-tree.cpp
-# add space after
-a
-
-.
-$i
-  ft_add(1, 1, 1);
-  ft_add(1, 2, 3);
-  ft_add(1, 3, 9);
-  ft_add(2, 1, 5);
-  ft_add(2, 2, 5);
-  ft_add(2, 3, 8);
-
-  assert(ft_rsq(1, 1, 1, 1) == 1);
-  assert(ft_rsq(2, 2, 2, 2) == 5);
-  assert(ft_rsq(1, 1, 2, 2) == 1+3+5+5);
-  assert(ft_rsq(1, 1, 2, 3) == 1+3+9+5+5+8);
-.
-w
-EOF
diff --git a/testes/fenwick-tree.cpp b/testes/fenwick-tree.cpp
index b7b9d9a00ab426bdc28153779eb789eb97ed8e63..57dc6be7e1650757cf9a0786b651ae579673b44e 100644
--- a/testes/fenwick-tree.cpp
+++ b/testes/fenwick-tree.cpp
@@ -1,42 +1,13 @@
 #include <bits/stdc++.h>
 using namespace std; using ll = long long;
 
-#define $(X) {if (DEBUG) { \
-  cerr << __LINE__ << ":"; {x} cerr << endl;}}
-#define _(X) {cerr << #X << " = " << X << " ";}
+const int N = 1e5+15;
 
-const int N = 1e5 + 3;
-
-typedef vector<int> vi;
-
-int ft_n = N; // O(n)
-vi ftree(ft_n, 0); // 1-indexed
-
-void add /* O(lg n) */ (int i, int d) {
-  for (; i < ft_n; i += i & -i)
-    ftree[i] += d;
-}
-
-int query /* O(lg n) */ (int i) {
-  int sum = 0;
-  for (; i > 0; i -= i & -i)
-    sum += ftree[i];
-  return sum;
-}
-
-// 1: add + range_sum, query is query_upto
-int query_inclusive /* O(lg n) */ (int i, int j) {
-  return query(j) - query(i - 1);
-}
-
-// 2: range_add + query, query is query
-void add_inclusive (int a, int b, int d) {
-  add(a, d);
-  add(b + 1, -d);
-}
+#include "../fontes/fenwick-tree.h"
 
 int main() {
   ios::sync_with_stdio(0); cin.tie(0);
+
   add(1, 1);
   add(2, 3);
   add(3, 5);
@@ -47,16 +18,16 @@ int main() {
   add(8, 6);
   add(9, 2);
 
-  assert(range_query(1, 1) == 1);
-  assert(range_query(2, 2) == 3);
-  assert(range_query(3, 3) == 5);
-  assert(range_query(4, 4) == 6);
-  assert(range_query(5, 5) == 6);
-  assert(range_query(6, 6) == 9);
-  assert(range_query(7, 7) == 8);
-  assert(range_query(8, 8) == 6);
-  assert(range_query(9, 9) == 2);
-  assert(range_query(5, 8) == 6+9+8+6);
-  assert(range_query(1, 8) == 1+3+5+6+6+9+8+6);
-  assert(range_query(1, 9) == 1+3+5+6+6+9+8+6+2);
+  assert(sum_inclusive(1, 1) == 1);
+  assert(sum_inclusive(2, 2) == 3);
+  assert(sum_inclusive(3, 3) == 5);
+  assert(sum_inclusive(4, 4) == 6);
+  assert(sum_inclusive(5, 5) == 6);
+  assert(sum_inclusive(6, 6) == 9);
+  assert(sum_inclusive(7, 7) == 8);
+  assert(sum_inclusive(8, 8) == 6);
+  assert(sum_inclusive(9, 9) == 2);
+  assert(sum_inclusive(5, 8) == 6+9+8+6);
+  assert(sum_inclusive(1, 8) == 1+3+5+6+6+9+8+6);
+  assert(sum_inclusive(1, 9) == 1+3+5+6+6+9+8+6+2);
 }
diff --git a/testes/fenwick-tree.gen b/testes/fenwick-tree.gen
deleted file mode 100755
index 52356704bac1927192ef4c56fff9122c9945f70a..0000000000000000000000000000000000000000
--- a/testes/fenwick-tree.gen
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/sh
-ed -s testes/fenwick-tree.cpp <<'EOF'
-# toggle debug helper
-H
-# delete all lines
-,d
-# add template
-r fontes/template.cpp
-# find main
-/int main() {/
-# add info before main
-i
-const int N = 1e5 + 3;
-
-typedef vector<int> vi;
-
-.
-# add fenwick-tree right before that space
-.r fontes/fenwick-tree.cpp
-# add space after
-a
-
-.
-$i
-  add(1, 1);
-  add(2, 3);
-  add(3, 5);
-  add(4, 6);
-  add(5, 6);
-  add(6, 9);
-  add(7, 8);
-  add(8, 6);
-  add(9, 2);
-
-  assert(range_query(1, 1) == 1);
-  assert(range_query(2, 2) == 3);
-  assert(range_query(3, 3) == 5);
-  assert(range_query(4, 4) == 6);
-  assert(range_query(5, 5) == 6);
-  assert(range_query(6, 6) == 9);
-  assert(range_query(7, 7) == 8);
-  assert(range_query(8, 8) == 6);
-  assert(range_query(9, 9) == 2);
-  assert(range_query(5, 8) == 6+9+8+6);
-  assert(range_query(1, 8) == 1+3+5+6+6+9+8+6);
-  assert(range_query(1, 9) == 1+3+5+6+6+9+8+6+2);
-.
-w
-EOF
diff --git a/testes/hld-ps.cpp b/testes/hld-ps.cpp
index 9dfc45a054ce7c0da1535fe01edfa034b63e19d2..e1f4bbf315b83860e14b6c6a4a862084505a493e 100644
--- a/testes/hld-ps.cpp
+++ b/testes/hld-ps.cpp
@@ -1,124 +1,40 @@
 #include <bits/stdc++.h>
-using namespace std; using ll = long long;
+using namespace std;
+using ll = long long;
+using ii = pair<int, ll>;
 
-#define $(X) {if (DEBUG) { \
-  cerr << __LINE__ << ":"; {x} cerr << endl;}}
-#define _(X) {cerr << #X << " = " << X << " ";}
+const int N = 1e5+15;
 
-const int N = 1e5 + 3;
+vector<vector<ii>> g (N);
 
-vector<ll> prefix_sum(N+1, 0);
-vector<ll> origin(N); // origin has to be ll too
-
-void ps_build (int N) {
-  partial_sum(origin.begin(), origin.end(), prefix_sum.begin()+1);
-}
-
-// [a, b)
-ll ps_query (int a, int b) {
-  return prefix_sum[b] - prefix_sum[a];
-}
-
-ll ps_query_inclusive (int a, int b) {
-  return ps_query(a, b+1);
-}
-
-typedef vector<ll> vi;
-typedef pair<int, long> il;
-typedef vector<vector<il>> vvil;
-
-vvil graph (N);
-vi costs(N);
-vi heavy(N, -1), anc(N, -1);
-vi depth(N);
-
-int hld_fill /* O(V + E) */ (int u, int c) {
-  int w = 1, maxw = 0;
-  costs[u] = cost;
-  cost[u] = c;
-  for (auto e : graph[u]) {
-    int v, c;
-    tie(v, c) = e;
-    if (v != anc[u]) {
-      anc[v] = u;
-      depth[v] = depth[u] + 1;
-      int cw = hld_fill(v, c);
-      w += cw;
-      if (cw > maxw) {
-        maxw = cw;
-        heavy[u] = v;
-      }
-    }
-  }
-  return w;
-}
-
-vi hds(N), ixs(N);
-
-int cix = 1;
-
-void hld /* O(n lg n) */ (int u, int h = 1) {
-  hds[u] = h;
-  origin[cix] = costs[u];
-  origin[cix] = cost[u];
-  ixs[u] = cix++;
-
-  if (heavy[u] != -1)
-    hld(heavy[u], h); // continue chain
-
-  for (auto e : graph[u]) {
-    int v, c;
-    tie(v, c) = e;
-    if (v != anc[u] && v != heavy[u])
-      hld(v, v); // new chain
-  }
-}
-
-ll hld_sum /* O(lg^2 n) */ (int u, int v) {
-  ll answer = 0;
-  for (; hds[u] != hds[v]; v = anc[hds[v]]) {
-    if (depth[hds[u]] > depth[hds[v]]) swap(u, v);
-    ll path_sum = query_inclusive(ixs[hds[v]], ixs[v]);
-    answer += path_sum;
-  }
-  if (depth[u] > depth[v]) swap(u, v);
-
-  // Remove +1 if values are associated with vertices
-  return answer + query_inclusive(ixs[u] + 1, ixs[v]);
-}
+#define OP(X, Y) ((X) + (Y))
+#include "../fontes/prefix-sum.h"
+#define op_inclusive sum_inclusive
+#include "../fontes/hld.h"
 
 int main() {
   ios::sync_with_stdio(0); cin.tie(0);
 
-  int N;
-  while (cin >> N, N != 0) {
-    for (int i = 0; i < N+1; i++)
-      graph[i].clear();
+  int n;
+  while (cin >> n && n) {
+    for (int u = 0; u < n; u++)
+      g[u].clear();
 
-    fill(parents.begin(), parents.end(), -1);
-    fill(heavy.begin(), heavy.end(), -1);
-
-    for (int a = 1; a <= N - 1; a++) {
-      int b, t;
-      cin >> b >> t;
-      graph[a].push_back(il(b, t));
-      graph[b].push_back(il(a, t));
+    for (int a = 1; a < n; a++) {
+      int b, t; cin >> b >> t;
+      g[a].push_back(ii(b, t));
+      g[b].push_back(ii(a, t));
     }
 
-    cix = 1;
-
-    hld_fill(1, 0);
-    hld(1, 1);
-    ps_build(cix);
-
-    int Q;
-    cin >> Q;
+    hld_init(0);
 
-    for (int i = 0; i < Q; i++) {
-      int a, b;
-      cin >> a >> b;
-      if (i != 0) cout << " ";
-      cout << hld_sum(a, b);
+    bool first = true;
+    int q; cin >> q;
+    while (q--) {
+      int a, b; cin >> a >> b;
+      if (!first) cout << " ";
+      first = false;
+      cout << hld_op(a, b);
     }
 
     cout << "\n";
diff --git a/testes/hld-ps.gen b/testes/hld-ps.gen
deleted file mode 100755
index 6cdaf50706a6ccddac65a4a0659849f3966d2b7a..0000000000000000000000000000000000000000
--- a/testes/hld-ps.gen
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/bin/sh
-ed -s testes/hld-ps.cpp <<'EOF'
-# toggle debug helper
-H
-# delete all lines
-,d
-# add template
-r fontes/template.cpp
-# find main
-/int main() {/
-# add info before main
-i
-const int N = 1e5 + 3;
-
-.
-# add prefix-sum right before that space
-.r fontes/prefix-sum.cpp
-# add space after
-a
-
-ll ps_query_inclusive (int a, int b) {
-  return ps_query(a, b+1);
-}
-
-.
-# add content before
-i
-
-typedef vector<ll> vi;
-typedef pair<int, long> il;
-typedef vector<vector<il>> vvil;
-
-vvil graph (N);
-vi costs(N);
-.
-# add heavy-light-decomposition after
-.r fontes/heavy-light-decomposition.cpp
-# patch hld_fill with cost
-,s/hld_fill \(.\+\) (int u)/hld_fill \1 (int u, int cost)/
-# find maxw line
-/maxw/
-# add costs patch after
-a
-  costs[u] = cost;
-.
-# patch for from hld_fill
-.,+2s/for (auto v : graph\[u\])/for (auto e : graph[u])/
-a
-    int v, c;
-    tie(v, c) = e;
-.
-# patch hld_fill function call
-.,+5s/hld_fill(v)/hld_fill(v, c)/
-# patch for from hld
-/void hld /
-/hds/
-a
-  origin[cix] = costs[u];
-.
-/void hld /
-.,+9s/for (auto v : graph\[u\])/for (auto e : graph[u])/
-a
-    int v, c;
-    tie(v, c) = e;
-.
-# patch hld_query
-/ll hld_sum /
-.,+12s/query(/ps_query_inclusive(/
-$i
-
-  int N;
-  while (cin >> N, N != 0) {
-    for (int i = 0; i < N+1; i++)
-      graph[i].clear();
-
-    fill(parents.begin(), parents.end(), -1);
-    fill(heavy.begin(), heavy.end(), -1);
-
-    for (int a = 1; a <= N - 1; a++) {
-      int b, t;
-      cin >> b >> t;
-      graph[a].push_back(il(b, t));
-      graph[b].push_back(il(a, t));
-    }
-
-    cix = 1;
-
-    hld_fill(1, 0);
-    hld(1, 1);
-    ps_build(cix);
-
-    int Q;
-    cin >> Q;
-
-    for (int i = 0; i < Q; i++) {
-      int a, b;
-      cin >> a >> b;
-      if (i != 0) cout << " ";
-      cout << hld_sum(a, b);
-    }
-
-    cout << "\n";
-  }
-.
-w
-EOF
diff --git a/testes/lazy-segment-tree.cpp b/testes/lazy-segment-tree.cpp
deleted file mode 100644
index b57d05ec004024b2692444ccbb56fb35e845a16e..0000000000000000000000000000000000000000
--- a/testes/lazy-segment-tree.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-#include <bits/stdc++.h>
-using namespace std; using ll = long long;
-
-#define $(X) {if (DEBUG) { \
-  cerr << __LINE__ << ":"; {x} cerr << endl;}}
-#define _(X) {cerr << #X << " = " << X << " ";}
-
-#define OP(X, Y) (X + Y)
-#define NEUTRAL 0
-#define FACTOR (tb - ta + 1)
-
-const int N = 1e5 + 3;
-
-#define LEFT 2*i
-#define RIGH 2*i+1
-
-struct node {
-  int data = 0;
-
-  node() {};
-  node(int x) { data = x; };
-
-  node operator+(const node& a) {
-    node n; n.data = a.data + data; return n;
-  };
-  node operator+=(const int& a) {
-    data += a; return *this;
-  };
-};
-
-const int N = 1e5+15;
-const int LOG = ceil(log2(N));
-
-struct dlta { int add = 0, set = -1; };
-
-vector<ll> stree(2*N), origin(N);
-vector<dlta> delta(2*N);
-
-ll apply(int i, dlta d, int sz) {
-    if (d.set != -1) {
-        stree[i] = d.set * sz;
-        delta[i] = { 0, d.set };
-    }
-    if (d.add != 0) {
-        stree[i] += d.add * sz;
-        delta[i].add += d.add;
-    }
-    return stree[i];
-}
-
-void pull(int p) {
-    for (int s = __builtin_ctz(p)+1; s < LOG; s++) {
-        int i = p >> s;
-        stree[i] = stree[LEFT] + stree[RIGH];
-    }
-}
-
-void push(int p) {
-    int sz = 1 << (LOG-1);
-    for (int s = LOG; s > 0; s--, sz /= 2) {
-        int i = p >> s;
-        apply(LEFT, delta[i], sz);
-        apply(RIGH, delta[i], sz);
-        delta[i] = {};
-    }
-}
-
-ll op_range(int l, int r, char op = '\0', ll x = 0) {
-    dlta d;
-    if (op == '+') { d.add = x; }
-    if (op == '=') { d.set = x; }
-    int tl = l += N, tr = r += N, sz = 1;
-    push(tl); push(tr);
-    ll ans = 0;
-    for (; l < r; l /= 2, r /= 2, sz *= 2) {
-        if (l & 1) ans += apply(l++, d, sz);
-        if (r & 1) ans += apply(--r, d, sz);
-    }
-    pull(tl); pull(tr);
-    return ans;
-}
-
-void build () {
-    for (int i = 0; i < N; i++)
-      stree[N+i] = origin[i];
-    for (int i = N-1; i > 0; i--)
-      stree[i] = stree[LEFT] + stree[RIGH];
-}
-int main() {
-  ios::sync_with_stdio(0); cin.tie(0);
-  op_range(1, 10, '+', 1);
-  op_range(1,  8, '+', 1);
-  op_range(2,  4, '+', 5);
-  op_range(3,  8, '+', 3);
-
-  op_range(1, 10, '=', 0);
-
-  assert(op_range(1, 1).data == 0);
-  assert(op_range(2, 2).data == 0);
-  assert(op_range(3, 3).data == 0);
-  assert(op_range(4, 4).data == 0);
-  assert(op_range(5, 5).data == 0);
-  assert(op_range(6, 6).data == 0);
-  assert(op_range(7, 7).data == 0);
-  assert(op_range(8, 8).data == 0);
-  assert(op_range(9, 9).data == 0);
-
-  assert(op_range(5, 8).data == 0);
-  assert(op_range(1, 8).data == 0);
-  assert(op_range(1, 9).data == 0);
-
-  op_range(1, 10, '+', 1);
-  op_range(1,  8, '+', 1);
-  op_range(2,  4, '+', 5);
-  op_range(3,  8, '+', 3);
-
-  assert(op_range(1, 1).data == 2);
-  assert(op_range(2, 2).data == 7);
-  assert(op_range(3, 3).data == 10);
-  assert(op_range(4, 4).data == 10);
-  assert(op_range(5, 5).data == 5);
-  assert(op_range(6, 6).data == 5);
-  assert(op_range(7, 7).data == 5);
-  assert(op_range(8, 8).data == 5);
-  assert(op_range(9, 9).data == 1);
-
-  assert(op_range(5, 8).data == 20);
-  assert(op_range(1, 8).data == 49);
-  assert(op_range(1, 9).data == 50);
-
-  op_range(1, 10, '+', 1);
-
-  assert(op_range(1, 1).data == 3);
-  assert(op_range(2, 2).data == 8);
-  assert(op_range(3, 3).data == 11);
-  assert(op_range(4, 4).data == 11);
-  assert(op_range(5, 5).data == 6);
-  assert(op_range(6, 6).data == 6);
-  assert(op_range(7, 7).data == 6);
-  assert(op_range(8, 8).data == 6);
-  assert(op_range(9, 9).data == 2);
-
-  assert(op_range(5, 8).data == 24);
-  assert(op_range(1, 8).data == 57);
-  assert(op_range(1, 9).data == 59);
-
-  op_range(1, 7, '=', 0);
-
-  assert(op_range(1, 1).data == 0);
-  assert(op_range(2, 2).data == 0);
-  assert(op_range(3, 3).data == 0);
-  assert(op_range(4, 4).data == 0);
-  assert(op_range(5, 5).data == 0);
-  assert(op_range(6, 6).data == 0);
-  assert(op_range(7, 7).data == 0);
-  assert(op_range(8, 8).data == 6);
-  assert(op_range(9, 9).data == 2);
-
-  assert(op_range(5, 7).data == 0);
-  assert(op_range(5, 8).data == 6);
-  assert(op_range(1, 8).data == 6);
-  assert(op_range(1, 9).data == 8);
-}
diff --git a/testes/lazy-segment-tree.gen b/testes/lazy-segment-tree.gen
deleted file mode 100755
index 38d6cf05573941d2c88bf852ff726062863a6537..0000000000000000000000000000000000000000
--- a/testes/lazy-segment-tree.gen
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/bin/sh
-ed -s testes/lazy-segment-tree.cpp <<'EOF'
-# toggle debug helper
-H
-#
-# delete all lines
-,d
-#
-# add template
-r fontes/template.cpp
-#
-# find main
-/int main() {/
-#
-# add info before main
-i
-#define OP(X, Y) (X + Y)
-#define NEUTRAL 0
-#define FACTOR (tb - ta + 1)
-
-const int N = 1e5 + 3;
-
-.
-#
-# add fenwick-tree right before that space
-.r fontes/lazy-segment-tree.cpp
-$i
-  op_range(1, 10, '+', 1);
-  op_range(1,  8, '+', 1);
-  op_range(2,  4, '+', 5);
-  op_range(3,  8, '+', 3);
-
-  op_range(1, 10, '=', 0);
-
-  assert(op_range(1, 1).data == 0);
-  assert(op_range(2, 2).data == 0);
-  assert(op_range(3, 3).data == 0);
-  assert(op_range(4, 4).data == 0);
-  assert(op_range(5, 5).data == 0);
-  assert(op_range(6, 6).data == 0);
-  assert(op_range(7, 7).data == 0);
-  assert(op_range(8, 8).data == 0);
-  assert(op_range(9, 9).data == 0);
-
-  assert(op_range(5, 8).data == 0);
-  assert(op_range(1, 8).data == 0);
-  assert(op_range(1, 9).data == 0);
-
-  op_range(1, 10, '+', 1);
-  op_range(1,  8, '+', 1);
-  op_range(2,  4, '+', 5);
-  op_range(3,  8, '+', 3);
-
-  assert(op_range(1, 1).data == 2);
-  assert(op_range(2, 2).data == 7);
-  assert(op_range(3, 3).data == 10);
-  assert(op_range(4, 4).data == 10);
-  assert(op_range(5, 5).data == 5);
-  assert(op_range(6, 6).data == 5);
-  assert(op_range(7, 7).data == 5);
-  assert(op_range(8, 8).data == 5);
-  assert(op_range(9, 9).data == 1);
-
-  assert(op_range(5, 8).data == 20);
-  assert(op_range(1, 8).data == 49);
-  assert(op_range(1, 9).data == 50);
-
-  op_range(1, 10, '+', 1);
-
-  assert(op_range(1, 1).data == 3);
-  assert(op_range(2, 2).data == 8);
-  assert(op_range(3, 3).data == 11);
-  assert(op_range(4, 4).data == 11);
-  assert(op_range(5, 5).data == 6);
-  assert(op_range(6, 6).data == 6);
-  assert(op_range(7, 7).data == 6);
-  assert(op_range(8, 8).data == 6);
-  assert(op_range(9, 9).data == 2);
-
-  assert(op_range(5, 8).data == 24);
-  assert(op_range(1, 8).data == 57);
-  assert(op_range(1, 9).data == 59);
-
-  op_range(1, 7, '=', 0);
-
-  assert(op_range(1, 1).data == 0);
-  assert(op_range(2, 2).data == 0);
-  assert(op_range(3, 3).data == 0);
-  assert(op_range(4, 4).data == 0);
-  assert(op_range(5, 5).data == 0);
-  assert(op_range(6, 6).data == 0);
-  assert(op_range(7, 7).data == 0);
-  assert(op_range(8, 8).data == 6);
-  assert(op_range(9, 9).data == 2);
-
-  assert(op_range(5, 7).data == 0);
-  assert(op_range(5, 8).data == 6);
-  assert(op_range(1, 8).data == 6);
-  assert(op_range(1, 9).data == 8);
-.
-w
-EOF
diff --git a/testes/lstit.cpp b/testes/lstit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ccf0cebbcaf9d7cdfe070f497df09296ab7da40e
--- /dev/null
+++ b/testes/lstit.cpp
@@ -0,0 +1,85 @@
+#include <bits/stdc++.h>
+using namespace std;
+using ll = long long;
+const int N = 1e5+15;
+#define OP(X, Y) ((X) + (Y))
+#define NEUTRAL 0
+#define FACTOR(sz) sz
+#include "../fontes/lstit.h"
+
+int main() {
+  ios::sync_with_stdio(0); cin.tie(0);
+
+  apply_inclusive(1, 10, '+', 1);
+  apply_inclusive(1,  8, '+', 1);
+  apply_inclusive(2,  4, '+', 5);
+  apply_inclusive(3,  8, '+', 3);
+
+  apply_inclusive(1, 10, '=', 0);
+
+  assert(op_inclusive(1, 1) == 0);
+  assert(op_inclusive(2, 2) == 0);
+  assert(op_inclusive(3, 3) == 0);
+  assert(op_inclusive(4, 4) == 0);
+  assert(op_inclusive(5, 5) == 0);
+  assert(op_inclusive(6, 6) == 0);
+  assert(op_inclusive(7, 7) == 0);
+  assert(op_inclusive(8, 8) == 0);
+  assert(op_inclusive(9, 9) == 0);
+
+  assert(op_inclusive(5, 8) == 0);
+  assert(op_inclusive(1, 8) == 0);
+  assert(op_inclusive(1, 9) == 0);
+
+  apply_inclusive(1, 10, '+', 1);
+  apply_inclusive(1,  8, '+', 1);
+  apply_inclusive(2,  4, '+', 5);
+  apply_inclusive(3,  8, '+', 3);
+
+  assert(op_inclusive(1, 1) == 2);
+  assert(op_inclusive(2, 2) == 7);
+  assert(op_inclusive(3, 3) == 10);
+  assert(op_inclusive(4, 4) == 10);
+  assert(op_inclusive(5, 5) == 5);
+  assert(op_inclusive(6, 6) == 5);
+  assert(op_inclusive(7, 7) == 5);
+  assert(op_inclusive(8, 8) == 5);
+  assert(op_inclusive(9, 9) == 1);
+
+  assert(op_inclusive(5, 8) == 20);
+  assert(op_inclusive(1, 8) == 49);
+  assert(op_inclusive(1, 9) == 50);
+
+  apply_inclusive(1, 10, '+', 1);
+
+  assert(op_inclusive(1, 1) == 3);
+  assert(op_inclusive(2, 2) == 8);
+  assert(op_inclusive(3, 3) == 11);
+  assert(op_inclusive(4, 4) == 11);
+  assert(op_inclusive(5, 5) == 6);
+  assert(op_inclusive(6, 6) == 6);
+  assert(op_inclusive(7, 7) == 6);
+  assert(op_inclusive(8, 8) == 6);
+  assert(op_inclusive(9, 9) == 2);
+
+  assert(op_inclusive(5, 8) == 24);
+  assert(op_inclusive(1, 8) == 57);
+  assert(op_inclusive(1, 9) == 59);
+
+  apply_inclusive(1, 7, '=', 0);
+
+  assert(op_inclusive(1, 1) == 0);
+  assert(op_inclusive(2, 2) == 0);
+  assert(op_inclusive(3, 3) == 0);
+  assert(op_inclusive(4, 4) == 0);
+  assert(op_inclusive(5, 5) == 0);
+  assert(op_inclusive(6, 6) == 0);
+  assert(op_inclusive(7, 7) == 0);
+  assert(op_inclusive(8, 8) == 6);
+  assert(op_inclusive(9, 9) == 2);
+
+  assert(op_inclusive(5, 7) == 0);
+  assert(op_inclusive(5, 8) == 6);
+  assert(op_inclusive(1, 8) == 6);
+  assert(op_inclusive(1, 9) == 8);
+}
diff --git a/testes/convex-hull.gen b/testes/monotone.cpp
old mode 100755
new mode 100644
similarity index 54%
rename from testes/convex-hull.gen
rename to testes/monotone.cpp
index 4677e3fc9c747d6987faa805d77bc0cee4fa0c7e..2c4e22247ec44a3708f298058a5b465532f4abda
--- a/testes/convex-hull.gen
+++ b/testes/monotone.cpp
@@ -1,72 +1,25 @@
-#!/bin/sh
-ed -s testes/convex-hull.cpp <<'EOF'
-# toggle debug helper
-H
-w
-# delete all lines
-,d
-# add template
-r fontes/template.cpp
-# find main
-/int main() {/
-i
-#define all(x) x.begin(), x.end()
-#define px real()
-#define py imag()
-#define mp make_pair
-typedef complex<double> pt;
-typedef vector<pt> vpt;
-.
-/int main() {/
-# add space before main
-i
+#include <bits/stdc++.h>
+using namespace std;
+using ll = long long;
+const double EPS = 1e-8;
+#include "../fontes/point.h"
+#include "../fontes/monotone.h"
 
-.
-# add convex-hull right before that space
-.r fontes/convex-hull.cpp
-ke
-# convex_hull -> convex_hull_ccw
-/vpt convex_hull/
-.,/^}/s/convex_hull/convex_hull_ccw/
-# copy convex_hull_ccw -> convex_hull_cw
-?vpt convex_hull_ccw?
-/vpt convex_hull_ccw/,/^}/t-1
-/vpt convex_hull_ccw/
-.,.s/convex_hull_ccw/convex_hull_cw/
-.,/^}/s/<= 0)/>= 0)/
-# copy convex_hull_cw => convex_hull_ccw_colinear
-?vpt convex_hull_cw?
-/vpt convex_hull_cw/,/^}/t-1
-/vpt convex_hull_cw/
-.,.s/convex_hull_cw/convex_hull_ccw_colinear/
-.,/^}/s/>= 0)/< 0)/
-# copy convex_hull_ccw_colinear => convex_hull_cw_colinear
-?vpt convex_hull_ccw_colinear?
-/vpt convex_hull_ccw_colinear/,/^}/t-1
-/vpt convex_hull_ccw_colinear/
-.,.s/convex_hull_ccw_colinear/convex_hull_cw_colinear/
-.,/^}/s/< 0)/> 0)/
-?vpt convex_hull_cw_colinear?i
-
-.
-# add space after
-'ea
-
-.
-$i
-  vpt convex;
+int main() {
+  ios::sync_with_stdio(0); cin.tie(0);
+  vector<pt> convex;
 
   // 1 |*   *
   // 0 |* * *
   // y +-----
   //  x 0 1 2
-  vpt points { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 } };
+  vector<pt> points { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 2, 1 } };
 
   // 1 |3   2
   // 0 |0 * 1
   // y +-----
   //  x 0 1 2
-  convex = convex_hull_ccw(points);
+  convex = convex_hull(points);
   assert(convex.size() == 4);
   assert(convex[0] == pt(0, 0));
   assert(convex[1] == pt(2, 0));
@@ -77,18 +30,18 @@ $i
   // 0 |0 * 3
   // y +-----
   //  x 0 1 2
-  convex = convex_hull_cw(points);
-  assert(convex.size() == 4);
-  assert(convex[0] == pt(0, 0));
-  assert(convex[1] == pt(0, 1));
-  assert(convex[2] == pt(2, 1));
-  assert(convex[3] == pt(2, 0));
+  // convex = convex_hull_cw(points);
+  // assert(convex.size() == 4);
+  // assert(convex[0] == pt(0, 0));
+  // assert(convex[1] == pt(0, 1));
+  // assert(convex[2] == pt(2, 1));
+  // assert(convex[3] == pt(2, 0));
 
   // 1 |4   3
   // 0 |0 1 2
   // y +-----
   //  x 0 1 2
-  convex = convex_hull_ccw_colinear(points);
+  convex = convex_hull(points, true);
   assert(convex.size() == 5);
   assert(convex[0] == pt(0, 0));
   assert(convex[1] == pt(1, 0));
@@ -100,15 +53,15 @@ $i
   // 0 |0 4 3
   // y +-----
   //  x 0 1 2
-  convex = convex_hull_cw_colinear(points);
-  assert(convex.size() == 5);
-  assert(convex[0] == pt(0, 0));
-  assert(convex[1] == pt(0, 1));
-  assert(convex[2] == pt(2, 1));
-  assert(convex[3] == pt(2, 0));
-  assert(convex[4] == pt(1, 0));
+  // convex = convex_hull_cw_colinear(points);
+  // assert(convex.size() == 5);
+  // assert(convex[0] == pt(0, 0));
+  // assert(convex[1] == pt(0, 1));
+  // assert(convex[2] == pt(2, 1));
+  // assert(convex[3] == pt(2, 0));
+  // assert(convex[4] == pt(1, 0));
 
-  vpt ten_by_ten_grid;
+  vector<pt> ten_by_ten_grid;
 
   // 9 |* * * * * * * * * *
   // 8 |* * * * * * * * * *
@@ -138,7 +91,7 @@ $i
   // 0 |0 * * * * * * * * 1
   // y +-------------------
   //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_ccw(ten_by_ten_grid);
+  convex = convex_hull(ten_by_ten_grid);
   assert(convex.size() == 4);
   assert(convex[0] == pt(0., 0.));
   assert(convex[1] == pt(9., 0.));
@@ -157,12 +110,12 @@ $i
   // 0 |0 * * * * * * * * 3
   // y +-------------------
   //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_cw(ten_by_ten_grid);
-  assert(convex.size() == 4);
-  assert(convex[0] == pt(0., 0.));
-  assert(convex[1] == pt(0., 9.));
-  assert(convex[2] == pt(9., 9.));
-  assert(convex[3] == pt(9., 0.));
+  // convex = convex_hull_cw(ten_by_ten_grid);
+  // assert(convex.size() == 4);
+  // assert(convex[0] == pt(0., 0.));
+  // assert(convex[1] == pt(0., 9.));
+  // assert(convex[2] == pt(9., 9.));
+  // assert(convex[3] == pt(9., 0.));
 
   // 9 |R Q P O N M L K J I
   // 8 |S * * * * * * * * H
@@ -176,7 +129,7 @@ $i
   // 0 |0 1 2 3 4 5 6 7 8 9
   // y +-------------------
   //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_ccw_colinear(ten_by_ten_grid);
+  convex = convex_hull(ten_by_ten_grid, true);
   assert(convex.size() == 36);
   for (int i = 0; i < 9; i++) assert(convex[i+9*0] == pt(i-0, 0.));
   for (int i = 0; i < 9; i++) assert(convex[i+9*1] == pt(9., i-0));
@@ -195,12 +148,10 @@ $i
   // 0 |0 Z Y X W V U T S R
   // y +-------------------
   //  x 0 1 2 3 4 5 6 7 8 9
-  convex = convex_hull_cw_colinear(ten_by_ten_grid);
-  assert(convex.size() == 36);
-  for (int i = 0; i < 9; i++) assert(convex[i+9*0] == pt(0., i-0));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*1] == pt(i-0, 9.));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*2] == pt(9., 9-i));
-  for (int i = 0; i < 9; i++) assert(convex[i+9*3] == pt(9-i, 0.));
-.
-w
-EOF
+  // convex = convex_hull_cw_colinear(ten_by_ten_grid);
+  // assert(convex.size() == 36);
+  // for (int i = 0; i < 9; i++) assert(convex[i+9*0] == pt(0., i-0));
+  // for (int i = 0; i < 9; i++) assert(convex[i+9*1] == pt(i-0, 9.));
+  // for (int i = 0; i < 9; i++) assert(convex[i+9*2] == pt(9., 9-i));
+  // for (int i = 0; i < 9; i++) assert(convex[i+9*3] == pt(9-i, 0.));
+}