diff --git a/caderno.pdf b/caderno.pdf
index df4efc6e241440cbb102cc7850d3e8487d05652a..4b60aff95fa63be0f9c9d35e203505322483f7a7 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/caderno/caderno.tex b/caderno/caderno.tex
index 0e3a8e4ffd203ea7a4224774beac4a83d383caa2..1444998d3504c3d90635f11e8c6c9f4148ab0aca 100644
--- a/caderno/caderno.tex
+++ b/caderno/caderno.tex
@@ -368,6 +368,11 @@ para $a$ e $m$ coprimos.
 \importsource{stdtlca.h}
 
 \subsection{Empar. máximo bipartido -- Kuhn}
+\begin{tabular}{l}
+  \hline
+  As partes tem enumerações distintas
+  \\ \hline
+\end{tabular}
 \importsource{kuhn.h}
 
 \subsection{Empar. máximo bipartido -- Hopcroft}
@@ -386,7 +391,8 @@ para $a$ e $m$ coprimos.
 \subsection{Triângulo de Pascal}
 \importsource{pascal-triangle.h}
 
-\subsection{2-SAT*}
+\subsection{2-SAT}
+\importsource{2-sat.h}
 
 \subsection{Inclusão-Exclusão}
 \importsource{inclusion-exclusion.h}
@@ -397,7 +403,11 @@ para $a$ e $m$ coprimos.
 \subsection{Mínimo excluído}
 \importsource{mex.h}
 
-\subsection{Nímero*}
+\subsection{Nímero (Números de Grundy)}
+\importsource{grundy.h}
+
+\subsection{Jogo de Nim}
+\importsource{nim.h}
 
 \subsection{Euclides estendido/inv. multiplicativo}
 \begin{tabular}{l}
@@ -421,7 +431,13 @@ ax + by = c
 \end{align*}
 \importsource{diophantine.h}
 
-\subsection{Multiplicação -- Karatsuba*}
+\subsection{Multiplicação -- Karatsuba}
+\begin{tabular}{l}
+  \hline
+  $\bigO(n^{\log_3 n})$ \\
+\hline
+\end{tabular}
+\importsource{karatsuba.h}
 
 \subsection{Números de Catalão}
 \importsource{catalan.h}
@@ -490,33 +506,55 @@ ax + by = c
 \end{tabular}
 \importsource{linearsieve.h}
 
-\subsection{Exponenciação binária*}
+\subsection{Exponenciação binária}
 \importsource{binary-pow.h}
 
-\subsection{Exponenciação de matrizes*}
-\importsource{matrix-mult.cpp}
-
-\subsection{Miller-Rabin*}
+\subsection{Miller-Rabin}
+\importsource{miller-rabin.h}
 
-\subsection{Pollard Rho*}
+\subsection{Pollard Rho}
+\begin{tabular}{l}
+  \hline
+  $\bigO(n^{1/4})$ \\
+\hline
+\end{tabular}
+\importsource{pollardrho.h}
 
-\subsection{Teorema chinês do resto*}
+\subsection{Fibonacci}
+\importsource{fibonacci.h}
 
-\subsection{Fibonacci*}
+\subsection{Teorema chinês do resto}
+\begin{tabular}{l}
+  \hline
+  $\bigO(t \lg(m_1 m_2 \ldots m_t))$ \\
+\hline
+\end{tabular}
+\importsource{crt.h}
 
-\subsection{Teorema chinês do resto generalizado*}
+\subsection{Teorema chinês do resto generalizado}
+\begin{tabular}{l|l}
+  \hline
+  $\bigO(t \lg(m_1 m_2 \ldots m_t))$ &
+  Infinitas soluções $\pm \text{lcm}(m_1m_2\ldots m_t)$
+  \\ \hline
+\end{tabular}
+\importsource{noncoprimecrt.h}
 
 \section{Strings}
 
 \subsection{Árvore de sufixos}
-\importsource{suffix-tree.h}
+\importsource{st.h}
 
-\subsection{Aho-Corasick*}
+\subsection{Aho-Corasick}
 \importsource{acs.h}
 
-\subsection{Algoritmo Z*}
+\subsection{Autômato de Sufixo}
+\importsource{saut.h}
+
+\subsection{Algoritmo Z}
+$z[i]$ é o tamanho da maior string que é ao mesmo tempo, um prefixo de $s$ e um prefixo do sufixo de $s$ começando em $i$.
 
-\subsection{Autômato de Sufixo*}
+\importsource{z.h}
 
 \subsection{KMP}
 \begin{tabular}{l|l}
@@ -527,14 +565,17 @@ ax + by = c
 \end{tabular}
 \importsource{kmp.h}
 
-\subsection{Autômato KMP*}
+\subsection{Autômato KMP}
+\importsource{kmp-automaton.h}
 
 \subsection{Rabin-Karp}
 \importsource{rabinkarp.h}
 
-\subsection{Vetor de sufixos*}
+\subsection{Vetor de sufixos}
+\importsource{sa.h}
 
-\subsection{Vetor de sufixos com ordenação por contagem*}
+\subsection{Vetor de sufixos radix}
+\importsource{sar.h}
 
 \subsection{Trie}
 \importsource{trie.h}
@@ -560,21 +601,32 @@ ax + by = c
 \end{tabular}
 \importsource{graham.h}
 
-\subsection{Interseção de retângulos*}
+\subsection{Interseção de retângulos}
+\importsource{rectangle-intersection.h}
 
-\subsection{Polígono é convexo?*}
+\subsection{Ponto dentro do polígono?}
+\importsource{isinsidepoly.h}
 
-\subsection{Ponto dentro do polígono?*}
+\subsection{Ponto dentro do polígono convexo?}
+\importsource{isinsidepolyconvex.h}
 
-\subsection{Área de polígono*}
+\subsection{Área de polígono}
+\importsource{polyarea.h}
 
-\subsection{Área de polígono de pontos inteiros*}
+\subsection{Pontos inteiros no polígono}
+\begin{align*}
+A = i + b/2 - 1
+\end{align*}
+\importsource{latticepoints.h}
 
-\subsection{Distância de segmento e segmento*}
+\subsection{Segmento}
+\importsource{seg.h}
 
-\subsection{Distância de ponto e segmento*}
+\subsection{Ponto e segmento}
+\importsource{pointseg.h}
 
-\subsection{Intersecção de segmento*}
+\subsection{Segmento e segmento}
+\importsource{segseg.h}
 
 \subsection{Árvore KD}
 \importsource{kd-tree.h}
@@ -587,8 +639,6 @@ ax + by = c
 \section{Problemas}
 \subsection{Rainhas no tabuleiro*}
 
-\subsection{Jogo de Nim*}
-
 \subsection{Soma em subvetor*}
 
 \subsection{Remoção de valores com deque*}
@@ -617,8 +667,8 @@ ax + by = c
 
 \subsection{PD de perfil quebrado*}
 
-\subsection{Busca binária*}
-\importsource{binary-search.cpp}
+\subsection{Busca binária}
+\importsource{bs.h}
 
 \subsection{Busca binária diferentona*}
 
diff --git a/fontes/2-sat.h b/fontes/2-sat.h
new file mode 100644
index 0000000000000000000000000000000000000000..41a938dcf42ef914a034be5f112105fe89f9ef0d
--- /dev/null
+++ b/fontes/2-sat.h
@@ -0,0 +1,47 @@
+vector<vector<int>> g (2*N), g_t (2*N);
+vector<int> rep (2*N), vis (2*N);
+vector<bool> val (N);
+stack<int> sinks;
+int cts = 0;
+
+void fill_stack(int u) {
+  if (vis[u] == cts) { return; }
+  vis[u] = cts;
+  for (int v : g[u])
+    fill_stack(v);
+  sinks.push(u);
+}
+
+void mark_component(int u, int r) {
+  if (vis[u] == cts) { return; }
+  vis[u] = cts; rep[u] = r;
+  for (int v : g_t[u])
+    mark_component(v, r);
+}
+
+int solve2sat(int n) {
+  cts++;
+  for (int u = 0; u < 2*n; u++) { fill_stack(u); }
+  cts++;
+  int c = 0;
+  while (!sinks.empty()) {
+    int u = sinks.top(); sinks.pop();
+    mark_component(u, c++);
+  }
+  for (int u = 0; u < n; u++) {
+    if (rep[2*u] == rep[2*u+1])
+      return false;
+    val[u] = rep[2*u] > rep[2*u+1];
+  }
+  return true;
+}
+
+void add_implies(int a, bool na, int b, bool nb) {
+  a = 2*a+na; b = 2*b+nb;
+  g[a].push_back(b); g_t[b].push_back(a);
+}
+
+void add_disj(int a, bool na, int b, bool nb) {
+  add_implies(a, !na, b, nb);
+  add_implies(b, !nb, a, na);
+}
diff --git a/fontes/angular-sweep.h b/fontes/angular-sweep.h
index 0eee34be1519a0230ae60ff3646f7a1a66b26444..99a756699ab6c09c453951866ac19c7889be8a9b 100644
--- a/fontes/angular-sweep.h
+++ b/fontes/angular-sweep.h
@@ -1,4 +1,4 @@
-int get_points_inside (int i, double r, int n) {
+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) {
diff --git a/fontes/binary-pow.h b/fontes/binary-pow.h
index 537f1481fadbe720902d3d4e05e96259af57e3e6..f9e74e7143fee75941a6bc04763e2f501d2f4e30 100644
--- a/fontes/binary-pow.h
+++ b/fontes/binary-pow.h
@@ -1,7 +1,7 @@
-ll fast_pow (ll& res, ll a, ll e) {
+ll binary_pow(ll& res, ll a, ll e) {
   if (e == 0) { return res = 1; }
   if (e == 1) { return res = a; }
-  /* ll res = */ fast_pow(res, a, e/2);
+  /* ll res = */ binary_pow(res, a, e/2);
   res = res * res;
   if (e % 2) res = res * a;
   return res;
diff --git a/fontes/binary-search.cpp b/fontes/bs.h
similarity index 71%
rename from fontes/binary-search.cpp
rename to fontes/bs.h
index 35161a1a58d3018c335291a1b4230aacc1f792f0..d761a7d724b9b576a769ef5208cca47b096707cd 100644
--- a/fontes/binary-search.cpp
+++ b/fontes/bs.h
@@ -1,6 +1,6 @@
-int binary_search (int lo, int hi) {
+ll binary_search(ll lo, ll hi) {
   while (lo < hi) {
-    int mid = lo + (hi-lo) / 2;
+    ll mid = lo + (hi-lo) / 2;
     if (P(mid)) {
       hi = mid;
     } else {
diff --git a/fontes/chinese-remainder-theorem.cpp b/fontes/chinese-remainder-theorem.cpp
deleted file mode 100644
index f187f3e96a2dba49c93339e00b5bf8fa1fad10d6..0000000000000000000000000000000000000000
--- a/fontes/chinese-remainder-theorem.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// O(t lg lcm(m1, m2, ... m_t))
-// Infinitely many solutions can be found by +/- lcm(m1, m2, ..) x
-
-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) {
-  gans e = ext_gcd(n, m);
-
-  if ((a - b) % e.d != 0)
-    return {-1,-1}; // No solution
-
-  ll lcm = (m/e.d) * n;
-  ll ans = norm(a + e.x*(b-a) / e.d % (m/e.d)*n, lcm);
-  return {norm(ans, lcm), lcm};
-}
-
-ll crt(vector<ll> a, vector<ll> m) {
-  ll ans = a[0];
-  ll lcm = m[0];
-
-  int t = a.size();
-  for (int i = 1; i < t; ++i) {
-    auto ss = crt_single(ans, lcm, a[i], m[i]);
-    if (ss.first == -1)
-      return -1; // No solution
-
-    ans = ss.first;
-    lcm = ss.second;
-  }
-
-  return ans;
-}
diff --git a/fontes/crt.h b/fontes/crt.h
new file mode 100644
index 0000000000000000000000000000000000000000..266a3a2fbf715c95cb94ef62bd7e0e68dcf3ca80
--- /dev/null
+++ b/fontes/crt.h
@@ -0,0 +1,9 @@
+ll crt(vector<ll> a, vector<ll> m, int t) {
+  ll p = 1; for (ll& mi : m) { p *= mi; }
+  ll ans = 0;
+  for (int i = 0; i < t; i++) {
+    ll pp = p / m[i];
+    ans = (ans + ((a[i] * inv(pp, m[i])) % p * pp) % p) % p;
+  }
+  return ans;
+}
diff --git a/fontes/fibonacci.h b/fontes/fibonacci.h
new file mode 100644
index 0000000000000000000000000000000000000000..419312c5a4944ae963f92c38c428a2222a4c3583
--- /dev/null
+++ b/fontes/fibonacci.h
@@ -0,0 +1,19 @@
+using mat = vector<vector<ll>>;
+
+void mat_mul(mat& res, mat a) { mat b = res;
+  for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++)
+    res[i][j] = ((a[i][0]*b[0][j]) % M
+        + (a[i][1]*b[1][j]) % M) % M;
+}
+
+void fast_pow(mat& res, mat a, int b) {
+  if (b == 1) { res = a; return; }
+  fast_pow(res, a, b/2);
+  mat_mul(res, res); if (b % 2) { mat_mul(res, a); }
+}
+
+int fibonacci(int n) {
+  mat x {{ 1, 1 }, { 1, 0 }};
+  fast_pow(x, x, n);
+  return x[0][0];
+}
diff --git a/fontes/grundy.cpp b/fontes/grundy.cpp
deleted file mode 100644
index 6c6c092207e0dc140bdb298ca0b0f60526c614c3..0000000000000000000000000000000000000000
--- a/fontes/grundy.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#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/grundy.h b/fontes/grundy.h
new file mode 100644
index 0000000000000000000000000000000000000000..6979766c3bb0e8ad49394c3ea9642a423f6f0a5d
--- /dev/null
+++ b/fontes/grundy.h
@@ -0,0 +1,10 @@
+void grundy() {
+  vector<int> g (N, -1);
+  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();
+  }
+}
diff --git a/fontes/hopcroft.h b/fontes/hopcroft.h
index ff08c1c758ef5dce60764032473bbf4e1c0b3eb5..da76bb88c76f96257f1148cb13fbdd5bc77e720c 100644
--- a/fontes/hopcroft.h
+++ b/fontes/hopcroft.h
@@ -1,3 +1,4 @@
+vector<vector<int>> g (L);
 vector<int> matchl (L, -1), matchr (R, -1);
 vector<int> dist (L);
 
@@ -32,9 +33,9 @@ bool dfs(int l) {
   return false;
 }
 
-int hopcroft(int l) {
+int hopcroft(int ln) {
   int ans = 0;
-  while (bfs(l)) for (int u = 0; u < l; u++)
-    if (matchl[u] == -1 && dfs(u)) { ans++; }
+  while (bfs(ln)) for (int l = 0; l < ln; l++)
+    if (matchl[l] == -1 && dfs(l)) { ans++; }
   return ans;
 }
diff --git a/fontes/isinsidepoly.h b/fontes/isinsidepoly.h
new file mode 100644
index 0000000000000000000000000000000000000000..2d34a1bc9ce2b4bacb881f4b1739a4e6cdc6d75e
--- /dev/null
+++ b/fontes/isinsidepoly.h
@@ -0,0 +1,13 @@
+int is_inside_poly(vector<pt>& ps, pt p, int strict) {
+  int n = ps.size();
+  if (n < 3) { return false; }
+  int count = 0;
+  for (int i = 0; i < n; i++) {
+    int j = (i+1)%n;
+    if (on_segment(seg(ps[i], ps[j]), p))
+      return strict;
+    count ^= (((p.py < ps[i].py) - (p.py < ps[j].py))
+        * ord_ornt(seg(ps[i], ps[j]), p)) > 0;
+  }
+  return count;
+}
diff --git a/fontes/isinsidepolyconvex.h b/fontes/isinsidepolyconvex.h
new file mode 100644
index 0000000000000000000000000000000000000000..4cff718a7e7a8c4242943f6f70b9e3da8803e783
--- /dev/null
+++ b/fontes/isinsidepolyconvex.h
@@ -0,0 +1,10 @@
+bool is_inside_poly(vector<pt>& ps, pt p) {
+  int n = ps.size();
+  double theta = 0;
+  for (int i = 0; i < n; i++) {
+    theta += (seg_ornt(ps[i], ps[(i+1)%n], p)
+        >= 0 ? +1 : -1)
+      * angle(ps[i], p, ps[(i+1)%n]);
+  }
+  return abs(theta - 2*PI) < EPS;
+}
diff --git a/fontes/iterative-lazy-segment-tree.cpp b/fontes/iterative-lazy-segment-tree.cpp
deleted file mode 100644
index a9cd9fea9d13aee21fdddd3a8c21f9e29641f392..0000000000000000000000000000000000000000
--- a/fontes/iterative-lazy-segment-tree.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-#define N 1<<17
-#define LEFT 2*i
-#define RIGH 2*i+1
-#define M (ta+tb)/2
-
-struct segtree {
-  int n, h;
-  struct node t[2 * N];
-  struct node_update d[N];
-  struct node (*merge)(struct node*, struct node*);
-  struct node_update (*merge_upd)(struct node_update*, struct node_update*);
-  struct node (*apply_upd)(struct node*, struct node_update*);
-  bool (*upd_done)(struct node_update*);
-  void (*upd_clear)(struct node_update*);
-
-  void init() {
-    irof(i, 0, n) t[i] = tr->merge(&t[LEFT], &t[RIGH]);
-    fori(i, 0, N) upd_clear(&d[i]);
-  }
-
-  void apply (int p, struct node_update* upd) {
-    t[p] = apply_upd(t[p], upd);
-    if (p < n) d[p] = merge_upd(&d[p], upd);
-  }
-
-  void build (int i) {
-    while (i > 1) {
-      i /= 2;
-      t[i] = OP(&t[LEFT], &tr->t[RIGH]);
-      t[i] = apply_upd(&t[p], &d[p]);
-    }
-  }
-
-  void push (int p) {
-    irof(s, 0, h+1) {
-      int i = p >> s;
-      if (!upd_done(&d[i])) {
-        apply(tr, LEFT, &d[i]);
-        apply(tr, RIGH, &d[i]);
-        upd_clear(&d[i]);
-      }
-    }
-  }
-
-  void set_range (int l, int r, struct node_update* upd) {
-    l += n, r += n;
-    push(l);
-    push(r - 1);
-    int l0 = l, r0 = r;
-    for (; l < r; l /= 2, r /= 2) {
-      if (l & 1) apply(tr, l++, upd);
-      if (r & 1) apply(tr, --r, upd);
-    }
-    build(l0);
-    build(r0 - 1);
-  }
-
-  T query_range (int l, int r) {
-    l += n, r += n;
-    push(l); push(r - 1);
-    T r1 = NEUTRAL, r2 = NEUTRAL;
-    for (; l < r; l /= 2, r /= 2) {
-      if (l & 1) r1 = OP(r1, t[l++]);
-      if (r & 1) r2 = OP(t[--r], r2);
-    }
-    return OP(r1, r2);
-  }
-};
diff --git a/fontes/karatsuba.h b/fontes/karatsuba.h
new file mode 100644
index 0000000000000000000000000000000000000000..d3ca7812bf8ed49036f288b68073c93891158a43
--- /dev/null
+++ b/fontes/karatsuba.h
@@ -0,0 +1,42 @@
+vector<ll> karatsuba(const vector<ll> &a,
+    const vector<ll> &b) {
+  int n = a.size();
+  vector<ll> res(n + n);
+
+  if (n <= 32) {
+    for (int i = 0; i < n; i++)
+      for (int j = 0; j < n; j++)
+        res[i + j] += a[i] * b[j];
+
+    return res;
+  }
+
+  int k = n >> 1;
+  vector<ll> a1(a.begin(), a.begin() + k);
+  vector<ll> a2(a.begin() + k, a.end());
+  vector<ll> b1(b.begin(), b.begin() + k);
+  vector<ll> b2(b.begin() + k, b.end());
+
+  vector<ll> a1b1 = karatsuba(a1, b1);
+  vector<ll> a2b2 = karatsuba(a2, b2);
+
+  for (int i = 0; i < k; i++)
+    a2[i] += a1[i];
+  for (int i = 0; i < k; i++)
+    b2[i] += b1[i];
+
+  vector<ll> r = karatsuba(a2, b2);
+  for (int i = 0; i < a1b1.size(); i++)
+    r[i] -= a1b1[i];
+  for (int i = 0; i < a2b2.size(); i++)
+    r[i] -= a2b2[i];
+
+  for (int i = 0; i < r.size(); i++)
+    res[i + k] += r[i];
+  for (int i = 0; i < a1b1.size(); i++)
+    res[i] += a1b1[i];
+  for (int i = 0; i < a2b2.size(); i++)
+    res[i + n] += a2b2[i];
+
+  return res;
+}
diff --git a/fontes/kmp-automaton.cpp b/fontes/kmp-automaton.cpp
deleted file mode 100644
index c7c95d3fde31045ceb2477d1e7c88f5a814d0638..0000000000000000000000000000000000000000
--- a/fontes/kmp-automaton.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-dp[i, c] = {
-  i+1, se i < |needle| && needle[i] == c
-  dp[pi(i), c], senão
-}
-
-dp[i, c] = {
-  (i+1, 0), se i < |needle|-1 && needle[i] == c
-  (i+1, 1), se i == |needle| && needle[i] == c
-  (dp[pi(i), c], 0), senão
-}
-
-Mesmo padrão:
-
-s_3 = s_1 + s_2
-
-nxt_3[i] = nxt_2[nxt_1[i]]
-occ_3[i] = occ_1[i] + occ_2[nxt_1[i]]
diff --git a/fontes/kmp-automaton.h b/fontes/kmp-automaton.h
new file mode 100644
index 0000000000000000000000000000000000000000..c07a6c82e53427c54f68536b435a13db9de5a935
--- /dev/null
+++ b/fontes/kmp-automaton.h
@@ -0,0 +1,16 @@
+void compute_automaton(string s, vector<vector<int>>& aut) {
+  s += '#';
+  int n = s.size();
+  vector<int> pi = pre(s);
+  aut.assign(n, vector<int>(26));
+  for (int i = 0; i < n; i++) {
+    for (int c = 0; c < 26; c++) {
+      int j = i;
+      while (j > 0 && 'a' + c != s[j])
+        j = pi[j-1];
+      if ('a' + c == s[j])
+        j++;
+      aut[i][c] = j;
+    }
+  }
+}
diff --git a/fontes/latticepoints.h b/fontes/latticepoints.h
new file mode 100644
index 0000000000000000000000000000000000000000..07fcbf13d44a91555c65776390dcc5309971f058
--- /dev/null
+++ b/fontes/latticepoints.h
@@ -0,0 +1,15 @@
+ll lattice_points(vector<pt>& ps) {
+  ll b = 0;
+  for (int i = 0; i < n; i++) {
+    pt v = vec(ps[i], ps[(i+1)%n]);
+    if (v.py == 0) {
+      b += abs(v.px);
+    } else if (v.px == 0) {
+      b += abs(v.py);
+    } else {
+      b += gcd(abs(v.px), abs(v.py));
+    }
+  }
+
+  return poly_area(ps) - b/2 + 1;
+}
diff --git a/fontes/matrix-mult.cpp b/fontes/matrix-mult.cpp
deleted file mode 100644
index cba2df4449a676019e195128464e12a3585f9f02..0000000000000000000000000000000000000000
--- a/fontes/matrix-mult.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-void nsq (vvll& res, vvll& n) {
-  int i = 0, j = 0;
-  ll x = (n[i][0]*res[0][j]) % mod + (n[i][1]*res[1][j]) % mod;
-  i = 0, j = 1;
-  ll y = (n[i][0]*res[0][j]) % mod + (n[i][1]*res[1][j]) % mod;
-
-  res[0][0] = x % mod; res[0][1] = y % mod;
-}
diff --git a/fontes/maximum-bipartite-matching-hopcroft.cpp b/fontes/maximum-bipartite-matching-hopcroft.cpp
deleted file mode 100644
index 96e9cc15bb54d2428c0a24c85024bfd2875180fe..0000000000000000000000000000000000000000
--- a/fontes/maximum-bipartite-matching-hopcroft.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// Maximum bipartite matching
-// Hopcraft-Karp-Karzanov algorithm
-// O(E*sqrt(V))
-
-int L, R;
-vector<vector<int>> graph (L);
-vector<int> dist (L);
-vector<int> matchL (L, -1), matchR (R, -1);
-
-bool bfs() {
-  queue<int> Q;
-  for (int l = 0; l < L; ++l)
-    if (matchL[l] == -1) {
-      dist[l] = 0;
-      Q.push(l);
-    } else
-      dist[l] = -1;
-
-  bool ans = false;
-  while (!Q.empty()) {
-    int l = Q.front(); Q.pop();
-    for (auto r : graph[l])
-      if (matchR[r] == -1)
-        ans = true;
-      else if (dist[matchR[r]] == -1) {
-        dist[matchR[r]] = dist[l] + 1;
-        Q.push(matchR[r]);
-      }
-  }
-
-  return ans;
-}
-
-bool dfs(int l) {
-  if (l == -1)
-    return true;
-
-  for (auto r : graph[l])
-    if (matchR[r] == -1 ||
-        dist[matchR[r]] == dist[l] + 1)
-      if (dfs(matchR[r])) {
-        matchR[r] = l;
-        matchL[l] = r;
-        return true;
-      }
-
-  return false;
-}
-
-int hopcroft() {
-  int ans = 0;
-  while (bfs())
-    for (int l = 0; l < L; ++l)
-      if (matchL[l] == -1 && dfs(l))
-        ans++;
-
-  return ans;
-}
diff --git a/fontes/maximum-bipartite-matching-kuhn.cpp b/fontes/maximum-bipartite-matching-kuhn.cpp
deleted file mode 100644
index c870c53131a964ffe929f5a199e7f81f2e8bd8ee..0000000000000000000000000000000000000000
--- a/fontes/maximum-bipartite-matching-kuhn.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// Maximum bipartite matching
-// Kuhn-Munkres or Hungarian algorithm
-// O(V*E)
-
-// Bipartite, u and v are distinct enumerations
-vector<vector<int>> graph (1e4+1);
-vector<int> match (1e4+1, -1);
-vector<bool> visited(1e4+1);
-
-int dfs(int u) {
-  if (visited[u]) { return 0; }
-  visited[u] = true;
-
-  for (int v : graph[u]) {
-    if (match[v] == -1 || dfs(match[v])) {
-      match[v] = u;
-      return 1;
-    }
-  }
-
-  return 0;
-}
-
-int hungarian() {
-  int ans = 0;
-  for (int u = 0; u < n; u++) {
-    fill(visited.begin(), visited.end(), false);
-    ans += dfs(u);
-  }
-  return ans;
-}
diff --git a/fontes/miller-rabin.cpp b/fontes/miller-rabin.cpp
deleted file mode 100644
index 72337f7dac13eb3145ed15f033df14a9923dd802..0000000000000000000000000000000000000000
--- a/fontes/miller-rabin.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-using ll = long long;
-using i128 = __int128_t;
-
-ll fast_pow(ll a, ll e, ll m) {
-  if (e == 0) { return 1; }
-  if (e == 1) { return a; }
-  ll res = fast_pow(a, e/2, m);
-  res = (i128)res * res % m;
-  if (e % 2) res = (i128)res * a % m;
-  return res;
-}
-
-bool is_prime(ll n) {
-    if (n < 2) { return false; }
-    int s = __builtin_ctzll(n - 1);
-    ll d = n >> s;
-    for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
-        if (n == a) { return true; }
-        ll p = fast_pow(a, d, n), i = s;
-        while (p != 1 && p != n - 1 && a % n && i--)
-            p = (i128)p * p % n;
-        if (p != n - 1 && i != s)
-            return false;
-    }
-    return true;
-}
diff --git a/fontes/miller-rabin.h b/fontes/miller-rabin.h
new file mode 100644
index 0000000000000000000000000000000000000000..783e61e7d901c3f23094d27441065234f76afd54
--- /dev/null
+++ b/fontes/miller-rabin.h
@@ -0,0 +1,29 @@
+using ll = long long; using i128 = __int128_t;
+
+ll binary_pow(ll a, ll e, ll m) {
+  if (e == 0) { return 1; }
+  if (e == 1) { return a; }
+  ll res = binary_pow(a, e/2, m);
+  res = (i128)res * res % m;
+  if (e % 2) res = (i128)res * a % m;
+  return res;
+}
+
+vector<int> witnesses = {
+  // primes from 2 to 37, enough for 64 bits
+  2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37
+};
+
+bool is_prime(ll n) {
+  if (n < 2) { return false; }
+  int s = __lg((n-1)&-(n-1));
+  ll d = n >> s;
+  for (int a : witnesses) {
+    if (n == a) { return true; }
+    ll p = binary_pow(a, d, n), i = s;
+    while (p != 1 && p != n - 1 && a % n && i--)
+      p = (i128)p * p % n;
+    if (p != n - 1 && i != s) { return false; }
+  }
+  return true;
+}
diff --git a/fontes/misere.cpp b/fontes/misere.cpp
deleted file mode 100644
index 6298ac9f551a9ef7d938624315ae44a41cadb5b7..0000000000000000000000000000000000000000
--- a/fontes/misere.cpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#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/multiset.cpp b/fontes/multiset.cpp
deleted file mode 100644
index 7270cefc702d4b78bb308f69f2c8821a103a5393..0000000000000000000000000000000000000000
--- a/fontes/multiset.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-map<int, int> freq;
-for (int i = 0; i < n; i++) {
-    int x; cin >> x; freq[x]++; }
-vector<pair<int, int>> bag;
-for (auto f : freq)
-    bag.push_back(make_pair(f.second, f.first));
-sort(bag.rbegin(), bag.rend());
diff --git a/fontes/nim.cpp b/fontes/nim.cpp
deleted file mode 100644
index fa6f8bbe35ad400abc60579a8baeb847ac35fed1..0000000000000000000000000000000000000000
--- a/fontes/nim.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#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/nim.h b/fontes/nim.h
new file mode 100644
index 0000000000000000000000000000000000000000..299647b743f78c22eee3f9c57a23244cc5503e5e
--- /dev/null
+++ b/fontes/nim.h
@@ -0,0 +1,12 @@
+pair<int, int> solve_nim(vector<int> s) {
+  int n = s.size(), g = 0;
+  for (int i = 0; i < n; i++)
+    g ^= s[i];
+  if (g == 0) { return {-1, -1}; }
+  int msb = 1<<__lg(g);
+  for (int i = 0; i < n; i++) if (s[i]&msb) {
+    int t = s[i]^g;
+    return { s[i]-t, i+1 };
+  }
+  assert(0);
+}
diff --git a/fontes/noncoprimecrt.cpp b/fontes/noncoprimecrt.h
similarity index 57%
rename from fontes/noncoprimecrt.cpp
rename to fontes/noncoprimecrt.h
index 8ada3c3813001f80d52537185b86d3573bc30c7c..d09799492a82819d2d673ab5bf2cac40d0644d8f 100644
--- a/fontes/noncoprimecrt.cpp
+++ b/fontes/noncoprimecrt.h
@@ -1,15 +1,13 @@
-#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 crt(vector<ll> a, vector<ll> 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]);
@@ -17,10 +15,3 @@ ll crt /* O(t lg m1*..*mt) */ (vll a, vll m, int t) {
     }
     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/point-compression.cpp b/fontes/point-compression.cpp
deleted file mode 100644
index 72463c7507033ed0361455ffbd554b0deb01fe6f..0000000000000000000000000000000000000000
--- a/fontes/point-compression.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-void compress(int n, ll p, ll q) {
-  vector<pair<ll, int>> a (n);
-  for (int i = 0; i < n; i++) {
-    a[i] = make_pair(q*point[i].yy - p*point[i].xx, i);
-  }
-  sort(a.begin(), a.end());
-  for (int i = 0; i < n; i++) {
-    f[a[i].second] = i;
-  }
-}
diff --git a/fontes/pointseg.h b/fontes/pointseg.h
new file mode 100644
index 0000000000000000000000000000000000000000..c1dc5006525d21d7c471a34ed0a10f92bfe7fbb9
--- /dev/null
+++ b/fontes/pointseg.h
@@ -0,0 +1,12 @@
+pt point_in_seg(pt p, seg s) {
+  if (s.aa == s.bb) { return s.aa; }
+  double l = dot(vec(s.aa, p), vec(s)) / norm(vec(s));
+  if (l < 0.0) { return s.aa; }
+  if (l > 1.0) { return s.bb; }
+  return s.aa + l*vec(s);
+}
+
+bool on_segment(seg s, pt p) {
+  return cross(s.aa - p, s.bb - p) == 0
+    && dot(s.aa - p, s.bb - p) <= 0;
+}
diff --git a/fontes/pollardrho.h b/fontes/pollardrho.h
new file mode 100644
index 0000000000000000000000000000000000000000..1bf2067d84db7c7c321d5293938f900e989123d2
--- /dev/null
+++ b/fontes/pollardrho.h
@@ -0,0 +1,19 @@
+ll pollard(ll n) {
+  auto f = [n](ll x) {
+    return (fast_pow(x, x, n) + 1) % n;
+  };
+  if (n % 2 == 0) { return 2; }
+  for (ll i = 2; ; i++) {
+    ll x = i, y = f(x), p;
+    while ((p = gcd(n + y - x, n)) == 1)
+      x = f(x), y = f(f(y));
+    if (p != n) { return p; }
+  }
+}
+
+void factorize(vector<ll>& f, ll n) {
+  if (n == 1) { return; }
+  if (is_prime(n)) { f.push_back(n); return; }
+  ll x = pollard(n);
+  factorize(f, x); factorize(f, n/x);
+}
diff --git a/fontes/polyarea.h b/fontes/polyarea.h
new file mode 100644
index 0000000000000000000000000000000000000000..b249e0f7858229ed539117e3202bef3c95039ea1
--- /dev/null
+++ b/fontes/polyarea.h
@@ -0,0 +1,7 @@
+double polygon_area(vector<pt>& ps) {
+  double area = cross(ps[ps.size()-1], ps[0]);
+  for (int i = 1; i < ps.size(); i++) {
+    area += cross(ps[i-1], ps[i]);
+  }
+  return area / 2.0;
+}
diff --git a/fontes/rectangle-intersection.cpp b/fontes/rectangle-intersection.cpp
deleted file mode 100644
index 4b15b19f7cc8ed33d0b87f348a4b4054fc9f36f5..0000000000000000000000000000000000000000
--- a/fontes/rectangle-intersection.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-pt tl = pt(max(tl0.px, tl1.px), max(tl0.py, tl1.py));
-pt br = pt(min(br0.px, br1.px), min(br0.py, br1.py));
-
-bool has_intersection =
-    (make_pair(tl.px, tl.py) <= make_pair(br.px, br.py));
-int area = (br-tl).px * (br-tl).py
-
diff --git a/fontes/rectangle-intersection.h b/fontes/rectangle-intersection.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f2f88f605c142a36119f039e7313b62675c4655
--- /dev/null
+++ b/fontes/rectangle-intersection.h
@@ -0,0 +1,5 @@
+bool has_intersection(pt tl0, pt br0, pt tl1, pt br1) {
+  pt tl = pt(max(tl0.px, tl1.px), max(tl0.py, tl1.py));
+  pt br = pt(min(br0.px, br1.px), min(br0.py, br1.py));
+  return make_pair(tl.px, tl.py) <= make_pair(br.px, br.py);
+}
diff --git a/fontes/suffix-array-sort.cpp b/fontes/sa.h
similarity index 83%
rename from fontes/suffix-array-sort.cpp
rename to fontes/sa.h
index 798a95bec4b57499a48d55dc3cc8ef6e02ae7d48..3c210b34b9f6511ad0dc97c1118b345b406e9c88 100644
--- a/fontes/suffix-array-sort.cpp
+++ b/fontes/sa.h
@@ -1,11 +1,10 @@
 #define kk first
 #define ii second
 
-// O(n lg^2 n)
-vector<int> build_sa(int n, string s) {
+pair<vector<int>, vector<int>> build_sa(string s) {
+  int n = s.size();
   vector<int> sk (s.begin(), s.end());
-
-  vector<pair<ii, int>> a(n);
+  vector<pair<pair<int, int>, int>> a(n);
   for (int k = 1; k < n; k *= 2) {
     for (int i = 0; i < n; i++)
       a[i] = { { sk[i], sk[(i+k)%n] }, i };
@@ -14,10 +13,9 @@ vector<int> build_sa(int n, string s) {
     for (int i = 1, r = 0; i < n; i++)
       sk[a[i].ii] = a[i-1].kk == a[i].kk ? r : ++r;
   }
-
   vector<int> sa (n);
   for (int i = 0; i < n; i++) { sa[i] = a[i].ii; }
-  return sa;
+  return make_pair(sa, sk);
 }
 
 vector<int> compute_lcp (vector<int> sa, vector<int> sk) {
diff --git a/fontes/suffix-array-radix.cpp b/fontes/sar.h
similarity index 71%
rename from fontes/suffix-array-radix.cpp
rename to fontes/sar.h
index 8307ded4d8da574473e222c5b04a6ec71d3b899b..cb475a6fc6912f2fa810294817d3d804df7066a9 100644
--- a/fontes/suffix-array-radix.cpp
+++ b/fontes/sar.h
@@ -1,30 +1,26 @@
-vector<int> sk (n), sa (n);
-
-void build_sa(string s, int n) {
-  vector<ii> a (n);
+pair<vector<int>, vector<int>> build_sa(string s, int n) {
+  vector<int> sk (n), sa (n);
+  vector<pair<int, int>> a (n);
   for (int i = 0; i < n; i++) { a[i] = { s[i], i }; }
   sort(a.begin(), a.end());
   for (int i = 0; i < n; i++) { tie(sk[i], sa[i]) = a[i]; }
-
   vector<int> nsk(n);
   for (int i = 1, r = 0; i < n; i++)
     nsk[sa[i]] = (sk[i-1] == sk[i] ? r : ++r);
   sk.swap(nsk);
-
   for (int k = 1; k < n; k *= 2) {
     for (int i = 0; i < n; i++) { sa[i] = (sa[i]-k+n)%n; }
-
     vector<int> nsa(n), cnt(n+1);
     for (int x : sk) { cnt[x+1]++; }
     for (int i = 1; i < n; i++) { cnt[i] += cnt[i-1]; }
     for (int x : sa) { nsa[cnt[sk[x]]++] = x; }
     sa.swap(nsa);
-
     vector<int> nsk(n);
     for (int i = 1, r = 0; i < n; i++)
       nsk[sa[i]] =
-        ii(sk[sa[i-1]], sk[(sa[i-1]+k)%n]) ==
-        ii(sk[sa[i-0]], sk[(sa[i-0]+k)%n]) ? r : ++r;
+        make_pair(sk[sa[i-1]], sk[(sa[i-1]+k)%n]) ==
+        make_pair(sk[sa[i-0]], sk[(sa[i-0]+k)%n]) ? r : ++r;
     sk.swap(nsk);
   }
+  return make_pair(sa, sk);
 }
diff --git a/fontes/saut.h b/fontes/saut.h
new file mode 100644
index 0000000000000000000000000000000000000000..1802f4a3bb29e575bd830dbdaafb74d34ec2fb96
--- /dev/null
+++ b/fontes/saut.h
@@ -0,0 +1,62 @@
+int last = 0, sz = 1;
+vector<int> len (2*N), lnk (2*N), acc (2*N);
+vector<vector<int>> nxt (2*N, vector<int>(S));
+void add(int c) {
+  int cur = sz++; len[cur] = len[last]+1;
+  int p = last; last = cur;
+  for (; ~p && !nxt[p][c]; p = lnk[p])
+    nxt[p][c] = cur;
+  if (!~p) { lnk[cur] = 0; return; }
+  int q = nxt[p][c];
+  if (len[q] == len[p]+1) { lnk[cur] = q; return; }
+  int qq = sz++; len[qq] = len[p]+1; lnk[qq] = lnk[q];
+  copy(nxt[q].begin(), nxt[q].end(), nxt[qq].begin());
+  for (; ~p && nxt[p][c] == q; p = lnk[p])
+    nxt[p][c] = qq;
+  lnk[cur] = lnk[q] = qq;
+}
+
+void build(string& s) {
+  len[0] = 0, lnk[0] = -1;
+  for (char ch : s) { add(to_i(ch)); }
+  for (int u = last; u; u = lnk[u]) { acc[u] = 1; }
+}
+
+vector<int> cnt (2*N);
+vector<int> ord;
+void reverse_topo(int u) {
+  cnt[u] = 1;
+  for (int c = 0; c < S; c++) if (nxt[u][c])
+    if (!cnt[nxt[u][c]])
+      reverse_topo(nxt[u][c]);
+  ord.push_back(u);
+}
+void process_count() {
+  for (int u : ord) {
+    cnt[u] = 0;
+    for (int c = 0; c < S; c++) if (nxt[u][c])
+      cnt[u] += cnt[nxt[u][c]];
+    if (acc[u]) { cnt[u]++; }
+  }
+}
+
+int longest_common_substring(string& t) {
+  int u = 0, l = 0, ans = 0, pos = -1;
+  for (int i = 0; i < t.size(); i++) {
+    int c = t[i];
+    while (u && !nxt[u][c]) {
+      u = lnk[u]; l = len[u];
+    }
+    if (nxt[u][c]) { u = nxt[u][c]; l++; }
+    else { u = 0; l = 0; }
+    if (l > ans) { ans = l; pos = i; }
+  }
+  return ans;
+}
+
+int search(string& t) {
+  int u = 0; for (auto c : t) {
+    u = nxt[u][to_i(c)];
+    if (!u) { return 0; }}
+  return cnt[u];
+}
diff --git a/fontes/seg.h b/fontes/seg.h
new file mode 100644
index 0000000000000000000000000000000000000000..76171c0278bd7acd79c116f7da898d7fb9b2d65b
--- /dev/null
+++ b/fontes/seg.h
@@ -0,0 +1,7 @@
+#define aa first
+#define bb second
+using seg = pair<pt, pt>;
+pt vec(seg s) { return vec(s.aa, s.bb); }
+int ord_ornt(seg s, pt c) {
+    return seg_ornt(s.aa, s.bb, c);
+}
diff --git a/fontes/segseg.h b/fontes/segseg.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7902e08a07ea97898ac04de07d0b2c7a376c1a9
--- /dev/null
+++ b/fontes/segseg.h
@@ -0,0 +1,19 @@
+bool intersects_seg(seg s, seg t) {
+  int o1 = ord_ornt(s, t.aa), o2 = ord_ornt(s, t.bb);
+  int o3 = ord_ornt(t, s.aa), o4 = ord_ornt(t, s.bb);
+  return (
+    (o1 != o2 && o3 != o4) ||
+    (o1 == 0 && on_segment(s, t.aa)) ||
+    (o2 == 0 && on_segment(s, t.bb)) ||
+    (o3 == 0 && on_segment(t, s.aa)) ||
+    (o4 == 0 && on_segment(t, s.bb)));
+}
+
+double distance_seg_seg(seg s, seg t) {
+  if (intersects_seg(s, t)) { return 0; }
+  double v1 = distance_seg_point(s.aa, t);
+  double v2 = distance_seg_point(s.bb, t);
+  double v3 = distance_seg_point(t.aa, s);
+  double v4 = distance_seg_point(t.bb, s);
+  return min({ v1, v2, v3, v4 });
+}
diff --git a/fontes/suffix-tree.h b/fontes/st.h
similarity index 100%
rename from fontes/suffix-tree.h
rename to fontes/st.h
diff --git a/fontes/stair.cpp b/fontes/stair.cpp
deleted file mode 100644
index 3ff33125cfe15916497281e1a0b46c32cf1442a2..0000000000000000000000000000000000000000
--- a/fontes/stair.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#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/suffix-automaton.cpp b/fontes/suffix-automaton.cpp
deleted file mode 100644
index 1bfdd8d45033112895fb53248e3b096b0624843f..0000000000000000000000000000000000000000
--- a/fontes/suffix-automaton.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-struct suffix_automaton {
-  int last, sz;
-  vector<int> len, lnk, acc;
-  vector<vector<int>> nxt;
-
-  suffix_automaton() : len(2*MAX), lnk(2*MAX),
-  acc(2*MAX), nxt(2*MAX, vector<int>(26)) {}
-
-  void add(int c) {
-    int cur = sz++;
-    len[cur] = len[last]+1;
-    int p = last;
-    last = cur;
-    for (; ~p && !nxt[p][c]; p = lnk[p])
-      nxt[p][c] = cur;
-    if (!~p) { lnk[cur] = 0; return; }
-    int q = nxt[p][c];
-    if (len[q] == len[p]+1) { lnk[cur] = q; return; }
-    int qq = sz++;
-    len[qq] = len[p]+1;
-    lnk[qq] = lnk[q];
-    copy(nxt[q].begin(), nxt[q].end(), nxt[qq].begin());
-    for (; ~p && nxt[p][c] == q; p = lnk[p])
-      nxt[p][c] = qq;
-    lnk[cur] = lnk[q] = qq;
-  }
-
-  void build(string& s) {
-    last = 0, sz = 1;
-    len[0] = 0, lnk[0] = -1;
-    for (char ch : s) { add(ch-'A'); }
-    for (int u = last; u; u = lnk[u]) { acc[u] = 1; }
-  }
-
-  int longest_common_substring(string& t) {
-    int u = 0, l = 0, ans = 0, pos = -1;
-    for (int i = 0; i < t.size(); i++) {
-      while (u && !nxt[u][t[i]-'A']) {
-        u = lnk[u]; l = len[u];
-      }
-      if (nxt[u][t[i]-'A']) {
-        u = nxt[u][t[i]-'A'];
-        l++;
-      } else {
-        u = 0; l = 0;
-      }
-      if (l > ans) { ans = l; pos = i; }
-    }
-    return ans;
-  }
-};
diff --git a/fontes/z.h b/fontes/z.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d014fa0ff263d7b6768ede2c0418e86dfcb9438
--- /dev/null
+++ b/fontes/z.h
@@ -0,0 +1,13 @@
+vector<int> z_function(string s) {
+  int n = (int)s.length();
+  vector<int> z (n);
+  for (int i = 1, l = 0, r = 0; i < n; ++i) {
+    if (i <= r)
+      z[i] = min (r - i + 1, z[i - l]);
+    while (i + z[i] < n && s[z[i]] == s[i + z[i]])
+      ++z[i];
+    if (i + z[i] - 1 > r)
+      l = i, r = i + z[i] - 1;
+  }
+  return z;
+}