diff --git a/caderno/caderno.tex b/caderno/caderno.tex
index 69a50d616cbe191c20b4c08a34d7748fa7ec0f49..133c185fdb13644359c9e6af8032cccc1e026148 100644
--- a/caderno/caderno.tex
+++ b/caderno/caderno.tex
@@ -8,8 +8,10 @@
 \usepackage{amsmath}
 \usepackage{stfloats}
 \usepackage{caption}
+\usepackage{siunitx}
 \usepackage{multirow}
 \usepackage{fontspec}
+\usepackage{amssymb}
 \usepackage{hyperref}
 \usepackage{xcolor}
 \setmonofont[
@@ -168,6 +170,108 @@
 \end{align*}
 Para $p$ primo, $n_i$ e $m_i$ são coeficientes das representações de $n$ e $m$ na base $p$.
 
+\subsection{Teorema do Chicken McNugget}
+Dados dois números coprimos $n$ e $m$, o maior número que não pode ser escrito como
+uma combinação linear deles é $nm - n - m$.
+\begin{itemize}
+  \item Existem $\frac{(n-1)(m-1)}{2}$ inteiros não-negativos que não podem
+    ser escritos como uma combinação linear de $n$ e $m$.
+  \item Para cada par $(k, nm - n - m - k)$, para $k \ge 0$, exatamente um pode
+    ser escrito.
+\end{itemize}
+
+\subsection{Triplas pitagóricas}
+Para todo $a, b, c \in \mathbb{N}$ satisfazendo $a^2 + b^2 = c^2$, existem
+$m, n \in \mathbb{N}$ e $m > n$ de tal forma que:
+\begin{multicols}{3}
+  $$a = m^2 - n^2$$ \break
+  $$b = 2mn$$ \break
+  $$c = m^2 + n^2$$
+\end{multicols}
+
+\subsection{Razões trigonométricas}
+\begin{center}
+\begin{tabular}{cccc}
+  \hline
+  & $\ang{30}$ & $\ang{45}$ & $\ang{60}$ \\
+  \hline
+  $\sin \theta$ & $\frac{1}{2}$ & $\frac{\sqrt{2}}{2}$ & $\frac{\sqrt{3}}{2}$ \\
+  $\cos \theta$ & $\frac{\sqrt{3}}{2}$ & $\frac{\sqrt{2}}{2}$ & $\frac{1}{2}$ \\
+  $\tan \theta$ & $\frac{\sqrt{3}}{3}$ & $1$ & $\sqrt{3}$ \\
+  \hline
+\end{tabular}
+\end{center}
+
+\subsection{Soma de ângulos}
+\begin{align*}
+  \sin(a \pm b) = \sin a \cos b \pm \cos a \sin b \\
+  \cos(a \pm b) = \cos a \cos b \mp \sin a \sin b \\
+  \tan(a \pm b) = \frac{\tan a \pm \tan b}{1 \mp \tan a \tan b} \\
+\end{align*}
+
+\subsection{Grafos planarares}
+\begin{itemize}
+  \item Se $G$ tem $k$ componentes conectadas, então $n - m + f = k + 1$.
+  \item $m \le 3n - 6$. Se $G$ não tem triângulos, $m \le 2n - 4$.
+  \item O grau mínimo é $\le 5$. E pode ser 6-colorido em $\mathcal{O}(n+m)$.
+\end{itemize}
+
+\subsection{Corte mínimo}
+O corte mínimo pode ser encontrado em grafos não-direcionados com o algoritmo
+de Stoer-Wagner. Entre dois vértices, o Teorema do Fluxo Máximo e
+Corte Mínimo afirma que o fluxo máximo é igual ao peso total das arestas do
+custo mínimo. Para achar o corte, faça uma busca em profundidade partindo da
+fonte, percorrendo apenas as arestas com capacidade residual. Todos os
+vértices alcançados fazem parte de uma das partes do corte mínimo.
+
+\subsection{Fatorial e desarranjos}
+\begin{align*}
+  n! &\approxeq \sqrt{2\pi n} \left(\frac{n}{e}\right)^n \\
+  !n &= n!\sum_{i=0}^{n} \frac{(-1)^i)}{i!} \text{ para } n \ge 0 \\
+  !n &= \left\lfloor \frac{n! + 1}{e} \right\rfloor \text{ para } n \ge 1 \\
+  !n &= n(!(n-1)) + (-1)^n \text{ para } n > 0
+\end{align*}
+
+\subsection{Teorema binomial}
+\begin{align*}
+  (x + y)^n &= \sum_{k=0}^{n} \binom{n}{k} x^{n-k}y^k = \sum_{k=0}^{n} \binom{n}{k} x^ky^{n-k} \\
+  (x + 1)^n &= \sum_{k=0}^{n} \binom{n}{k} x^k
+\end{align*}
+
+\subsection{Círculo inscrito em triângulo}
+O centro do círculo forma três triângulos. A área do triângulo $ABC$ é igual a
+$\frac{rp}{2}$ onde $p$ é o perímetro do triângulo.
+
+\subsection{Lei dos senos}
+Dado um triângulo inscrito em um círculo de raio $r$, vale que
+\begin{align*}
+  \frac{a}{\sin A} = \frac{b}{\sin B} = \frac{c}{\sin C} = 2r
+\end{align*}
+
+\subsection{Lei dos cossenos}
+Triângulo $ABC$ com lados $a$, $b$ e $c$, a lei dos cossenos:
+\begin{align*}
+a^2 = b^2 + c^2 - 2bc \cdot \cos A
+\end{align*}
+E podemos derivar a inequalidade triangular:
+\begin{align*}
+  c^2 \le a^2 + b^2 + 2ab = (a + b)^2
+\end{align*}
+
+\subsection{Truque da distância Manhattan}
+Seja $\mathcal{L}((x, y)) = (x+y, x-y)$. Temos as seguintes funções de distância:
+\begin{itemize}
+  \item Manhattan: $M(p, q) = |p.x - q.x| + |p.y - q.y|$.
+  \item Chebyshev: $C(p, q) = \max(|p.x - q.x|, |p.y - q.y|)$.
+\end{itemize}
+Então:
+\begin{itemize}
+  \item $\mathcal{L}(\mathbb{Z}^2)$ escala $\mathbb{Z}^2$ em $\sqrt{2}$ e rotaciona em $\frac{\pi}{4}$ em sentido horário.
+  \item Para algum $p \in \mathbb{Z}^2$, $\mathcal{L}(\{ q : M(q, p) \le d \})$ (círculo) forma um quadrado alinhado
+    nos eixos em $\mathcal{L}(\mathbb{Z})^2$, com canto inferior-esquerda em $\mathcal{L}(p) - (d, d)$ e canto superior-direito em $\mathcal{L}(p) + (d, d)$.
+  \item $M(p, q) = C(\mathcal{L}(p), \mathcal{L}(q))$, e $C(p, q) = M(\mathcal{L}^{-1}(p), \mathcal{L}^{-1}(q))$.
+\end{itemize}
+
 \subsection{Números de Catalão}
 {\sloppy
 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,
@@ -335,6 +439,9 @@ para $a$ e $m$ coprimos.
 \subsection{Árvore de segmentos preguiçosa iter.}
 \lstinputlisting{fontes-com-hash/lazy-segment-tree.h}
 
+\subsection{Nó de Kadane}
+\lstinputlisting{fontes-com-hash/kadane.h}
+
 \subsection{Hash customizado}
 \lstinputlisting{fontes-com-hash/custom-hash.h}
 
@@ -351,8 +458,8 @@ para $a$ e $m$ coprimos.
 
 \subsection{Articulações e pontes}
 \lstinputlisting{fontes-com-hash/articulations-bridges.h}
-\clearpage
 
+\clearpage
 \subsection{Componentes fortes -- Tarjan}
 \lstinputlisting{fontes-com-hash/tarjan.h}
 
@@ -451,6 +558,9 @@ para $a$ e $m$ coprimos.
 \end{tabular}
 \lstinputlisting{fontes-com-hash/kuhn.h}
 
+\subsection{Emparelhamento Generalizado -- Blossom}
+\lstinputlisting{fontes-com-hash/blossom.h}
+
 \subsection{Decomposição raiz quadrada de árvore}
 \lstinputlisting{fontes-com-hash/tree-square-root-decomposition.h}
 
@@ -465,6 +575,9 @@ para $a$ e $m$ coprimos.
 \subsection{Inteiro modular}
 \lstinputlisting{fontes-com-hash/modular-integer.h}
 
+\subsection{Transformação de Fourier Modular}
+\lstinputlisting{fontes-com-hash/number-theoretic-transform.h}
+
 \subsection{Matriz}
 \lstinputlisting{fontes-com-hash/matrix.h}
 
@@ -668,6 +781,9 @@ $z[i]$ é o tamanho da maior string que é ao mesmo tempo, um prefixo de $s$ e u
 \end{tabular}
 \lstinputlisting{fontes-com-hash/monotone.h}
 
+\subsection{Medidor giratório}
+\lstinputlisting{fontes-com-hash/rotating-calipers.h}
+
 \subsection{Árvore KD}
 \lstinputlisting{fontes-com-hash/kd-tree.h}
 
diff --git a/fontes/binary-pow.h b/fontes/binary-pow.h
index f9e74e7143fee75941a6bc04763e2f501d2f4e30..6bfcaa366bc28e39f4d6a367ca75e78dc62216e0 100644
--- a/fontes/binary-pow.h
+++ b/fontes/binary-pow.h
@@ -1,8 +1,7 @@
-ll binary_pow(ll& res, ll a, ll e) {
-  if (e == 0) { return res = 1; }
-  if (e == 1) { return res = a; }
-  /* ll res = */ binary_pow(res, a, e/2);
-  res = res * res;
-  if (e % 2) res = res * a;
+mint binary_pow(mint a, ll e) {
+  if (e == 0) { return 1; }
+  mint res = binary_pow(a, e/2);
+  res *= res;
+  if (e % 2) { res *= a; }
   return res;
 }
diff --git a/fontes/blossom.h b/fontes/blossom.h
new file mode 100644
index 0000000000000000000000000000000000000000..e835c48ff96dda9b6772a48a8215f77348015798
--- /dev/null
+++ b/fontes/blossom.h
@@ -0,0 +1,67 @@
+int n;
+vector<int> match (N), par (N), base (N), vis (N);
+queue<int> q;
+
+void contract(int u, int v, bool first = 1) {
+  static vector<bool> bloss; static int l;
+  if (first) {
+    bloss = vector<bool>(n, 0);
+    vector<bool> ok (n, 0);
+    int k = u; l = v;
+    while (1) {
+      ok[k = base[k]] = 1;
+      if (match[k] == -1) break;
+      k = par[match[k]];
+    }
+    while (!ok[l = base[l]]) l = par[match[l]];
+  }
+  while (base[u] != l) {
+    bloss[base[u]] = bloss[base[match[u]]] = 1;
+    par[u] = v; v = match[u]; u = par[match[u]];
+  }
+  if (!first) { return; }
+  contract(v, u, 0);
+  for (int u = 0; u < n; u++) if (bloss[base[u]]) {
+    base[u] = l;
+    if (!vis[u]) { q.push(u); }
+    vis[u] = 1;
+  }
+}
+
+int getpath(int s) {
+  for (int i = 0; i < n; i++) base[i] = i, par[i] = -1, vis[i] = 0;
+  vis[s] = 1; q = queue<int>(); q.push(s);
+  while (q.size()) {
+    int u = q.front(); q.pop();
+    for (int i : g[u]) {
+      if (base[i] == base[u] || match[u] == i) { continue; }
+      if (i == s or (match[i] != -1 && par[match[i]] != -1))
+        contract(u, i);
+      else if (par[i] == -1) {
+        par[i] = u;
+        if (match[i] == -1) { return i; }
+        i = match[i];
+        vis[i] = 1; q.push(i);
+      }
+    }
+  }
+  return -1;
+}
+
+int blossom() {
+  int ans = 0;
+  fill(all(match), -1);
+  for (int i = 0; i < n; i++) if (match[i] == -1)
+    for (int j : g[i]) if (match[j] == -1) {
+      match[i] = j; match[j] = i; ans++; break;
+    }
+  for (int i = 0; i < n; i++) if (match[i] == -1) {
+    int j = getpath(i); if (j == -1) { continue; }
+    ans++;
+    while (j != -1) {
+      int p = par[j], pp = match[p];
+      match[p] = j; match[j] = p; j = pp;
+    }
+  }
+  return ans;
+}
diff --git a/fontes/kadane.h b/fontes/kadane.h
new file mode 100644
index 0000000000000000000000000000000000000000..76dec7c7df4505528e417d8f92294e13b15cfc14
--- /dev/null
+++ b/fontes/kadane.h
@@ -0,0 +1,13 @@
+struct kadane {
+  int sum, pref, suff, ans;
+  kadane() : sum(-oo) { pref = suff = ans = 0; }
+  kadane(int x) : sum(x) { pref = suff = ans = max(x, 0); }
+  kadane operator+(kadane const& r) {
+    auto l = *this; kadane a;
+    a.sum = max(l.sum + r.sum, -oo);
+    a.pref = max(l.pref, l.sum + r.pref);
+    a.suff = max(r.suff, r.sum + l.suff);
+    a.ans = max({ l.ans, r.ans, l.suff + r.pref });
+    return a;
+  }
+}
diff --git a/fontes/lazy-segment-tree.h b/fontes/lazy-segment-tree.h
index 7969c44ecb3741babd0b7e96483896b1ab6c088f..9ad17ad67e963b5a32d27d45eab7468a27280c73 100644
--- a/fontes/lazy-segment-tree.h
+++ b/fontes/lazy-segment-tree.h
@@ -3,7 +3,7 @@ struct dlta { int add = 0, set = -1; };
 vector<ll> t (2*N); vector<dlta> delta (2*N);
 
 void build(vector<int>& src, int n) {
-  for (int i = 1; i < src.size(); i++)
+  for (int i = 1; i <= n; i++)
     t[n+i] = src[i];
   for (int ti = n-1; ti > 0; ti--)
     t[ti] = OP(t[2*ti], t[2*ti+1]);
@@ -60,11 +60,10 @@ ll op_inclusive(int l, int r, int n) {
   r++;
   int tl = l += n, tr = r += n, sz = 1;
   push(tl); push(tr);
-  ll ans = NEUTRAL;
+  ll left = NEUTRAL, righ = 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));
+    if (l & 1) left = OP(left, apply(l++, dlta(), sz));
+    if (r & 1) righ = OP(apply(--r, dlta(), sz), righ);
   }
-  pull(tl); pull(tr);
-  return ans;
+  return OP(left, righ);
 }
diff --git a/fontes/number-theoretic-transform.h b/fontes/number-theoretic-transform.h
new file mode 100644
index 0000000000000000000000000000000000000000..db36cc319de5b6d16651d102429c56d6c5b93024
--- /dev/null
+++ b/fontes/number-theoretic-transform.h
@@ -0,0 +1,32 @@
+void ntt (vector<mint>& a, bool rev) {
+  int n = a.size(); auto b = a;
+  mint g = 1;
+  while (binary_pow(g, P/2) == 1) g += 1;
+  if (rev) { g = binary_pow(g.x, P-2); }
+
+  for (int st = n/2; st; st /= 2) {
+    mint w = binary_pow(g, P/(n/st)), wn = 1;
+    for (int i = 0; i < n/2; i += st) {
+      for (int j = 0; j < st; j++) {
+        auto u = a[2*i+j], v = wn * a[2*i+j+st];
+        b[i+j] = u + v; b[i+n/2+j] = u - v;
+      }
+      wn *= w;
+    }
+    swap(a, b);
+  }
+
+  mint n1 = binary_pow(n, P-2);
+  if (rev) for (mint& x : a) { x *= n1; }
+}
+
+vector<mint> convolution (vector<mint>& a, vector<mint>& b) {
+  vector<mint> fa (all(a)), fb (all(b));
+  int n = 1;
+  while (n < a.size() + b.size()) { n *= 2; }
+  fa.resize(n); fb.resize(n);
+  ntt(fa, 0); ntt(fb, 0);
+  for (int i = 0; i < n; i++) { fa[i] *= fb[i]; }
+  ntt(fa, 1);
+  return fa;
+}
diff --git a/fontes/rotating-calipers.h b/fontes/rotating-calipers.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c9a460f3cc8954565cb6474365021e05b25b121
--- /dev/null
+++ b/fontes/rotating-calipers.h
@@ -0,0 +1,23 @@
+ld abs_area(pt p, pt q, pt r) {
+  return abs((p.px*q.py + q.px*r.py + r.px*p.py) -
+    (p.py*q.px + q.py*r.px + r.py*p.px));
+}
+
+ld rotating_calipers(vector<pt>& ps) {
+  vector<pt> h = convex_hull(ps); int n = h.size();
+  if (n == 1) { return 0; }
+  if (n == 2) { return abs(h[0] - h[1]); }
+  int k = 1;
+  while (abs_area(h[n-1], h[0], h[(k+1)%n]) >
+      abs_area(h[n-1], h[0], h[k])) k++;
+  ld ans = 0;
+  for (int i = 0, j = k; i <= k; i++) {
+    while (abs_area(h[i], h[(i+1)%n], h[(j+1)%n]) >
+        abs_area(h[i], h[(i+1)%n], h[j])) {
+      ans = max(ans, abs(h[i] - h[(j+1)%n]));
+      j = (j+1) % n;
+    }
+    ans = max(ans, abs(h[i] - h[j]));
+  }
+  return ans;
+}
diff --git a/fontes/segment-tree.h b/fontes/segment-tree.h
index 1ed1d74754dd2c0ae6d903a26b7fd57cc6b5fb11..c9869545274e9d18f5f9b7e56331cd30f07bb009 100644
--- a/fontes/segment-tree.h
+++ b/fontes/segment-tree.h
@@ -1,20 +1,20 @@
 vector<int> t (2*N);
 
 void build(vector<int>& src, int n) {
-  for (int i = 1; i < src.size(); i++)
+  for (int i = 1; i <= n; i++)
     t[n+i] = src[i];
-  for (int i = n-1; i > 0; i--)
-    t[i] = OP(t[2*i], t[2*i+1]);
+  for (int ti = n-1; ti > 0; ti--)
+    t[ti] = OP(t[2*ti], t[2*ti+1]);
 }
 
 int op_inclusive(int l, int r, int n) {
   r++;
-  int left = NEUTRAL, right = NEUTRAL;
+  int left = NEUTRAL, righ = 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]);
+    if (r & 1) righ = OP(t[--r], righ);
   }
-  return OP(left, right);
+  return OP(left, righ);
 }
 
 void set_value(int i, int v, int n) {
diff --git a/fontes/suffix-tree.h b/fontes/suffix-tree.h
index cf5ae8a5d85d2c0e89c0ff375efebc536c32ef17..27a1fa2fce0cc7d0d82e68554a45aa10db72f97b 100644
--- a/fontes/suffix-tree.h
+++ b/fontes/suffix-tree.h
@@ -5,13 +5,13 @@ 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) {
+int mknode(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 root = mknode(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])])
@@ -19,14 +19,14 @@ void build(string s) {
     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);
+      nxt[u][id(s[j])] = mknode(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]);
+      int mi = mknode(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);
+      nxt[mi][id(s[j])] = mknode(j, s.size()-1, mi);
       if (ns) { suf[ns] = mi; }
       u = parent[mi]; int g;
       if (u != root)