diff --git a/caderno.pdf b/caderno.pdf
index c4990fc0b23c71cafc96aa03b9ea33e086bb1a1d..3793f3bb84675db5eb0b1fa265bb00a50374b406 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/caderno/caderno.tex b/caderno/caderno.tex
index 15ef3e5738d36e861ac594c7898c57f558f9afb8..0d1c000d5b9284df6f14c72cbed21c3346cbd2df 100644
--- a/caderno/caderno.tex
+++ b/caderno/caderno.tex
@@ -211,7 +211,7 @@ $m, n \in \mathbb{N}$ e $m > n$ de tal forma que:
   \tan(a \pm b) = \frac{\tan a \pm \tan b}{1 \mp \tan a \tan b} \\
 \end{align*}
 
-\subsection{Grafos planarares}
+\subsection{Grafos planares}
 \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$.
@@ -219,12 +219,12 @@ $m, n \in \mathbb{N}$ e $m > n$ de tal forma que:
 \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.
+O algoritmo de Stoer-Wagner acha o corte mínimo em grafos não-direcionados.
+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*}
@@ -290,7 +290,7 @@ Aplicações:
   \itemsep -2pt
   \item $C_n$ é o número de expressões contendo $n$ parênteses corretamente pareados.
   \item $C_n$ é o número de árvores binárias completas com $n+1$ folhas.
-  \item $C_n$ são as vezes que um polígono convexo com $n+2$ lados pode ser cortado em triângulos conectando os vérticese com linhas retas.
+  \item $C_n$ são as vezes que um polígono convexo com $n+2$ lados pode ser cortado em triângulos conectando os vértices e com linhas retas.
 \end{itemize}
 
 \subsection{Fórmula de Heron}
@@ -426,6 +426,9 @@ para $a$ e $m$ coprimos.
 \subsection{Nó de Kadane}
 \lstinputlisting{fontes-com-hash/kadane.h}
 
+\subsection{Nó de parênteses}
+\lstinputlisting{fontes-com-hash/paren.h}
+
 \section{Grafos}
 
 \subsection{Articulações e pontes}
@@ -446,6 +449,8 @@ para $a$ e $m$ coprimos.
 \subsection{Caminho mínimo -- Dijkstra}
 \lstinputlisting{fontes-com-hash/dijkstra.h}
 
+\clearpage
+
 \subsection{Caminho mínimo -- Bellman-Ford}
 \lstinputlisting{fontes-com-hash/bellman-ford.h}
 
@@ -461,9 +466,20 @@ para $a$ e $m$ coprimos.
 \subsection{Árvore geradora mínima -- Prim}
 \lstinputlisting{fontes-com-hash/prim.h}
 
+\subsection{Caminho euleriano}
+\lstinputlisting{fontes-com-hash/eulerian-path.h}
+
 \subsection{Menor no maior}
 \lstinputlisting{fontes-com-hash/small-to-large.h}
 
+\clearpage
+
+\subsection{Decomposição pesado-leve}
+\lstinputlisting{fontes-com-hash/hld.h}
+
+\subsection{Decomposição pesado-leve -- K-ésimo}
+\lstinputlisting{fontes-com-hash/hld-kth.h}
+
 \subsection{Fluxo máximo}
 \lstinputlisting{fontes-com-hash/ford-fulkerson-edmons-karp.h}
 
@@ -476,26 +492,17 @@ para $a$ e $m$ coprimos.
 \subsection{Stoer-Wagner}
 \lstinputlisting{fontes-com-hash/stoer-wagner.h}
 
-\subsection{Decomposição pesado-leve}
-\lstinputlisting{fontes-com-hash/hld.h}
-
-\subsection{Decomposição pesado-leve -- K-ésimo}
-\lstinputlisting{fontes-com-hash/hld-kth.h}
-
-\subsection{Caminho euleriano}
-\lstinputlisting{fontes-com-hash/eulerian-path.h}
-
 \subsection{Ascensão binária}
 \lstinputlisting{fontes-com-hash/binary-lifting.h}
 
 \subsection{Menor anc. comum -- Ancensão binária}
 \lstinputlisting{fontes-com-hash/lca-binary-lifting.h}
 
+\clearpage
+
 \subsection{Empar. máximo bipartido -- Kuhn}
 \lstinputlisting{fontes-com-hash/kuhn.h}
 
-\clearpage
-
 \subsection{Empar. generalizado -- Blossom}
 \lstinputlisting{fontes-com-hash/blossom.h}
 
@@ -505,14 +512,16 @@ para $a$ e $m$ coprimos.
 \subsection{Decomposição centróide}
 \lstinputlisting{fontes-com-hash/centroid.h}
 
-\subsection{Menor anc. comum -- Dec. raiz quad.}
-\lstinputlisting{fontes-com-hash/lca-square-root-decomposition.h}
+\subsection{Menor anc. comum -- Offline}
+\lstinputlisting{fontes-com-hash/lca-offline.h}
+
+\clearpage
 
 \subsection{Decomposição raiz quadrada de árvore}
 \lstinputlisting{fontes-com-hash/tree-square-root-decomposition.h}
 
-\subsection{Menor anc. comum -- Offline}
-\lstinputlisting{fontes-com-hash/lca-offline.h}
+\subsection{Menor anc. comum -- Dec. raiz quad.}
+\lstinputlisting{fontes-com-hash/lca-square-root-decomposition.h}
 
 \section{Matemática}
 
@@ -545,7 +554,7 @@ Número de sequências distintas:
 \end{align*}
 \lstinputlisting{fontes-com-hash/bruijn.h}
 
-\subsection{PD de Dígito}
+\subsection{PD de dígito}
 \lstinputlisting{fontes-com-hash/digit-dp.h}
 
 \subsection{Primeiros digitos de $n^k$}
@@ -557,13 +566,13 @@ Número de sequências distintas:
 \subsection{2-SAT}
 \lstinputlisting{fontes-com-hash/2-sat.h}
 
+\subsection{Multiplicação -- Karatsuba}
+\lstinputlisting{fontes-com-hash/karatsuba.h}
+
 \subsection{Truque de divisão}
 Gera um conjunto $n/i$ para todo $i$ em $\bigO(\sqrt{n})$.
 \lstinputlisting{fontes-com-hash/division-trick.h}
 
-\subsection{Multiplicação -- Karatsuba}
-\lstinputlisting{fontes-com-hash/karatsuba.h}
-
 \subsection{Inclusão-Exclusão}
 \lstinputlisting{fontes-com-hash/inclusion-exclusion.h}
 
@@ -623,9 +632,6 @@ ax + by = c
 \subsection{Pollard Rho}
 \lstinputlisting{fontes-com-hash/pollard-rho.h}
 
-\subsection{Teorema chinês do resto}
-\lstinputlisting{fontes-com-hash/chinese-remainder-theorem.h}
-
 \subsection{Teorema chinês do resto generalizado}
 \lstinputlisting{fontes-com-hash/generalized-chinese-remainder-theorem.h}
 
@@ -648,14 +654,14 @@ $z[i]$ é o tamanho da maior string que é ao mesmo tempo, um prefixo de $s$ e u
 \subsection{Autômato de Sufixo}
 \lstinputlisting{fontes-com-hash/suffix-automaton.h}
 
-\subsection{Aho-Corasick/Trie}
-\lstinputlisting{fontes-com-hash/aho-corasick.h}
+\subsection{Vetor de sufixos}
+\lstinputlisting{fontes-com-hash/suffix-array.h}
 
 \subsection{Vetor de sufixos radix}
 \lstinputlisting{fontes-com-hash/suffix-array-radix.h}
 
-\subsection{Vetor de sufixos}
-\lstinputlisting{fontes-com-hash/suffix-array.h}
+\subsection{Aho-Corasick/Trie}
+\lstinputlisting{fontes-com-hash/aho-corasick.h}
 
 \subsection{Árvore de sufixos}
 \lstinputlisting{fontes-com-hash/suffix-tree.h}
@@ -671,7 +677,7 @@ $z[i]$ é o tamanho da maior string que é ao mesmo tempo, um prefixo de $s$ e u
 \subsection{Fecho convexo com corrente monotônica}
 \lstinputlisting{fontes-com-hash/monotone.h}
 
-\subsection{Medidor giratório}
+\subsection{Distância máxima}
 \lstinputlisting{fontes-com-hash/rotating-calipers.h}
 
 \subsection{Árvore KD}
@@ -731,15 +737,15 @@ Para mudar para superconjunto, use \texttt{\~{}mask} no if.
 \subsection{Ordenação por fusão}
 \lstinputlisting{fontes-com-hash/merge-sort.h}
 
-\subsection{Agendamento ótimo de tarefas}
-\lstinputlisting{fontes-com-hash/optimal-schedule-jobs.h}
-
 \subsection{Algoritmo de Mo}
 \lstinputlisting{fontes-com-hash/mo-algorithm.h}
 
 \subsection{Meet in the middle}
 \lstinputlisting{fontes-com-hash/meet-in-the-middle.h}
 
+\subsection{Agendamento ótimo de tarefas}
+\lstinputlisting{fontes-com-hash/optimal-schedule-jobs.h}
+
 \subsection{Maior subsequência comum}
 \lstinputlisting{fontes-com-hash/longest-common-subsequence.h}
 
@@ -759,12 +765,14 @@ Para mudar para superconjunto, use \texttt{\~{}mask} no if.
 \subsection{Remoção de valores com deque}
 \lstinputlisting{fontes-com-hash/remove-deque.h}
 
-\subsection{Inversões usando algoritmo de Mo}
-\lstinputlisting{fontes-com-hash/inversion-mo.h}
-
 \subsection{Desembarcadouro}
 \lstinputlisting{fontes-com-hash/desembarcadouro.h}
 
+\clearpage
+
+\subsection{Inversões usando algoritmo de Mo}
+\lstinputlisting{fontes-com-hash/inversion-mo.h}
+
 \subsection{Média e mediana}
 \lstinputlisting{fontes-com-hash/mean-median.h}
 
@@ -774,4 +782,10 @@ Para mudar para superconjunto, use \texttt{\~{}mask} no if.
 \subsection{Código de Gray}
 \lstinputlisting{fontes-com-hash/gray-code.h}
 
+\subsection{Árvore de segmentos de GCD}
+\lstinputlisting{fontes-com-hash/gcd-add.h}
+
+\subsection{Distância em árvore}
+\lstinputlisting{fontes-com-hash/tree-distance.h}
+
 \end{document}
diff --git a/fontes/2-sat.h b/fontes/2-sat.h
index 013e40f5a8795a1870fd7eb6af3588a715348136..39a6f0342e777ae653aefcdbc955ab863779fb93 100644
--- a/fontes/2-sat.h
+++ b/fontes/2-sat.h
@@ -1,14 +1,11 @@
 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;
+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);
+  if (vis[u] == cts) { return; } vis[u] = cts;
+  for (int v : g[u]) { fill_stack(v); }
   sinks.push(u);
 }
 
@@ -27,8 +24,7 @@ int solve2sat(int n) {
     mark_component(u, c++);
   }
   for (int u = 0; u < n; u++) {
-    if (rep[2*u] == rep[2*u+1])
-      return 0;
+    if (rep[2*u] == rep[2*u+1]) { return 0; }
     val[u] = rep[2*u] > rep[2*u+1];
   }
   return 1;
diff --git a/fontes/aho-corasick.h b/fontes/aho-corasick.h
index 02c8662c6ccc950fcbcf25ffe6c74dad242694b1..cb52ef5dc0911c46a20cf537e92487b8bd7fd2d5 100644
--- a/fontes/aho-corasick.h
+++ b/fontes/aho-corasick.h
@@ -21,13 +21,11 @@ void ins(string ne, int 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)
@@ -35,7 +33,6 @@ int go(int u, int 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);
@@ -45,19 +42,16 @@ int out(int u) {
 
 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);
+  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)
+        // match ix<@\compl{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;
+      occ[ix] += aca[u].occ; // # of matches<@\compl{len}@>
 }
diff --git a/fontes/chinese-remainder-theorem.h b/fontes/chinese-remainder-theorem.h
deleted file mode 100644
index 801c79a265253d56ab2b30c6c7c717e81b422437..0000000000000000000000000000000000000000
--- a/fontes/chinese-remainder-theorem.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// infinite solutions <@$\pm \lcm(m_1m_2\ldots m_t)$@>
-//<@\compl{t \lg m_1m_2\ldots m_t}@>
-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 += ((a[i] * inv(pp, m[i])) % p * pp) % p;
-    ans %= p;
-  }
-  return ans;
-}
diff --git a/fontes/desembarcadouro.h b/fontes/desembarcadouro.h
index f2f008322f90997b359f584e7665d110daf6a304..2ff17db44cc7f286df71ab004b24c35569d037b6 100644
--- a/fontes/desembarcadouro.h
+++ b/fontes/desembarcadouro.h
@@ -7,7 +7,7 @@ int main() {
     int a, l, d; cin >> a >> l >> d;
     if (d >= K)
       for (int i = 0; i < l; i++) { c[a + i * d]++; }
-    else { dp[a][d]++; dp[a + (l * d)][d]--; }
+    else { dp[a][d]++; dp[a+(l*d)][d]--; }
   }
   for (int j = 1; j < K; j++)
     for (int i = j; i < n + 1; i++)
diff --git a/fontes/gcd-add.h b/fontes/gcd-add.h
new file mode 100644
index 0000000000000000000000000000000000000000..534588f40126a6baf54b028c9b3c1c4dfe399e27
--- /dev/null
+++ b/fontes/gcd-add.h
@@ -0,0 +1,28 @@
+int main() {
+  int n, q; cin >> n >> q;
+  gcdst_t gcdst; sumst_t sumst;
+  vector<ll> a (n+1), b (n+1);
+  for (int i = 1; i <= n; i++) {
+    cin >> a[i]; b[i] = a[i] - a[i-1];
+  }
+  gcdst.build(b, n); sumst.build(b, n);
+
+  while (q--) {
+    int t; cin >> t; int l, r; cin >> l >> r;
+    if (t == 1) {
+      ll v; cin >> v;
+      sumst.add_value(l, +v, n);
+      gcdst.add_value(l, +v, n);
+      if (r+1 <= n) {
+        sumst.add_value(r+1, -v, n);
+        gcdst.add_value(r+1, -v, n);
+      }
+    } else {
+      // <@$gcd(a_l, a_l+1, \ldots a_r)$@>
+      // <@$gcd(a_l, a_l+1 - a_l, a_l+2 - a_l+1, \ldots, a_r - a_r-1)$@>
+      ll first = sumst.op_inclusive(1, l, n);
+      ll ans = gcdst.op_inclusive(l+1, r, n);
+      cout << gcd(first, ans) << "\n";
+    }
+  }
+}
diff --git a/fontes/generalized-chinese-remainder-theorem.h b/fontes/generalized-chinese-remainder-theorem.h
index abd721e88d237a529b1510c0d987d5eaa5a77de7..3e420c622f2f1211cc817f95065fdd410db611b3 100644
--- a/fontes/generalized-chinese-remainder-theorem.h
+++ b/fontes/generalized-chinese-remainder-theorem.h
@@ -9,6 +9,8 @@ pair<ll, ll> crt_single(ll a, ll n, ll b, ll m) {
   return {norm(a + n*(x*(b-a)/g % (m/g)), lcm), lcm};
 }
 
+// infinite solutions <@$\pm \lcm(m_1m_2\ldots m_t)$@>
+//<@\compl{t \lg m_1m_2\ldots m_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) {
diff --git a/fontes/hld-kth.h b/fontes/hld-kth.h
index 933af43a5ccb0a21668f481e2ef9053df9709037..a09e577f46210762f42b09696635b6c21f0fa356 100644
--- a/fontes/hld-kth.h
+++ b/fontes/hld-kth.h
@@ -29,9 +29,8 @@ vector<int> hld_path(int u, int v, int k) {
   for (; hds[u] != hds[v]; v = par[hds[v]]) {
     if (dep[hds[u]] > dep[hds[v]])
       { swap(u, v); sw ^= 1; }
-    for (int i = ixs[v]; i >= ixs[hds[v]]; i--) {
+    for (int i = ixs[v]; i >= ixs[hds[v]]; i--)
       path[sw ? l++ : r--] = rixs[i];
-    }
   }
   if (dep[u] > dep[v]) { swap(u, v); sw ^= 1; }
   for (int i = ixs[v]; i >= ixs[u]; i--) {
diff --git a/fontes/kd-tree.h b/fontes/kd-tree.h
index 81b44b042d4d04a81ebeb311a6076dca4f659b2a..709d7d6f5cf8439b12ad602b08a84204a1a7a86a 100644
--- a/fontes/kd-tree.h
+++ b/fontes/kd-tree.h
@@ -1,7 +1,5 @@
 int get_ii(pt pair, int ix) {
-  if (ix == 0) { return pair.px; }
-  else { return pair.py; }
-}
+  return ix == 0 ? pair.px : pair.py; }
 
 struct kdtree {
   struct node {
@@ -9,8 +7,7 @@ struct kdtree {
     double dist_sq(const pt& o) { return norm(o - p); }
     pt p; node* left, *right;
   };
-  node* root = 0;
-  vector<double> best; vector<node> t;
+  node* root = 0; vector<double> best; vector<node> t;
 
   struct cmp {
     size_t ix; cmp(size_t _index) : ix(_index) {}
diff --git a/fontes/number-theoretic-transform.h b/fontes/number-theoretic-transform.h
index 3c813db35120a6b65e34b440ad3179b2cfad01fc..fe9febc1304ddd50c5465129084f76b994a1e685 100644
--- a/fontes/number-theoretic-transform.h
+++ b/fontes/number-theoretic-transform.h
@@ -8,10 +8,8 @@ void ntt(vector<mint>& a, bool rev) { //<@\compl{n \lg n}@>
     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;
-    }
+        b[i+j] = u + v; b[i+n/2+j] = u - v; }
+      wn *= w; }
     swap(a, b);
   }
   mint n1 = binary_pow(n, P-2);
diff --git a/fontes/paren.h b/fontes/paren.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc4b66f325eb46083d1b370125e328c7795e6450
--- /dev/null
+++ b/fontes/paren.h
@@ -0,0 +1,15 @@
+struct node {
+  int open; int closed; int ans;
+  explicit node(char c) : open(0), closed(0), ans(0) {
+    if (c == '(') { open = 1; }
+    if (c == ')') { closed = 1; }
+  }
+  node operator+(node r) {
+    node a (0);
+    int mn = min(open, r.closed);
+    a.ans = ans + r.ans + mn;
+    a.open = open - mn + r.open;
+    a.closed = r.closed - mn + closed;
+    return a;
+  }
+};
diff --git a/fontes/suffix-array.h b/fontes/suffix-array.h
index 5b29aae60acade5118ac692023d7d73c91a2a1ec..574f8be8fcba27db6fc168ce51922d3997d72be0 100644
--- a/fontes/suffix-array.h
+++ b/fontes/suffix-array.h
@@ -2,14 +2,12 @@
 #define ii second
 
 pair<vector<int>, vector<int>> build_sa(string s) {
-  int n = s.size();
-  vector<int> sk (all(s));
+  int n = s.size(); vector<int> sk (all(s));
   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 };
-    sort(begin(a), end(a));
-    sk[a[0].ii] = 0;
+    sort(begin(a), end(a)); sk[a[0].ii] = 0;
     for (int i = 1, r = 0; i < n; i++)
       sk[a[i].ii] = a[i-1].kk == a[i].kk ? r : ++r;
   }
@@ -19,15 +17,11 @@ pair<vector<int>, vector<int>> build_sa(string s) {
 }
 
 vector<int> make_lcp(vector<int> sa, vector<int> sk) {
-  vector<int> lcp (n);
-  int k = 0;
+  vector<int> lcp (n); int k = 0;
   for (int i = 0; i < n-1; i++) {
-    int pi = sk[i];
-    int j = sa[pi-1];
-    // lcp[i] = lcp[s[i..], s[j..])
+    int pi = sk[i]; int j = sa[pi-1];
     while (s[i+k] == s[j+k]) k++;
-    lcp[pi] = k;
-    k = max(k - 1, 0);
+    lcp[pi] = k; k = max(k - 1, 0);
   }
   return lcp;
 }
diff --git a/fontes/suffix-tree.h b/fontes/suffix-tree.h
index 27a1fa2fce0cc7d0d82e68554a45aa10db72f97b..c57d246a4ef8ee19aa396dd5f9f6df769df80ea5 100644
--- a/fontes/suffix-tree.h
+++ b/fontes/suffix-tree.h
@@ -1,16 +1,13 @@
 vector<vector<int>> nxt (N, vector<int>(5));
 vector<int> 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 at(string& s, int i, int j) { return id(s[l[i] + j]); }
 int cur = 1;
 int mknode(int a, int b, int p) {
   l[cur] = a, r[cur] = b; parent[cur] = p;
   return cur++;
 }
-void build(string s) {
-  s += '$';
+void build(string s) { s += '$';
   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++) {
@@ -29,16 +26,12 @@ void build(string s) {
       nxt[mi][id(s[j])] = mknode(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; }
+      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;
-      }
+        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/tree-distance.h b/fontes/tree-distance.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b973e376e58e6578352dbf7bfb85f2f497a56af
--- /dev/null
+++ b/fontes/tree-distance.h
@@ -0,0 +1,30 @@
+vector<int> vis (N), dist (N), distix (N), dist2 (N);
+int cts = 1;
+
+void insert_max_dist(int u, int val, int ix) {
+  if (val > dist[u]) {
+    dist2[u] = dist[u]; dist[u] = val; distix[u] = ix;
+  } else {
+    dist2[u] = max(dist2[u], val);
+  }
+}
+
+void dfs_down(int u) {
+  vis[u] = cts;
+  for (int v : g[u]) if (vis[v] != cts) {
+    dfs_down(v); insert_max_dist(u, 1 + dist[v], v);
+  }
+}
+
+void dfs_up(int u) {
+  vis[u] = cts;
+  for (int v : g[u]) if (vis[v] != cts) {
+    int d = (distix[u] != v ? dist[u] : dist2[u]);
+    insert_max_dist(v, 1 + d, u);
+    dfs_up(v);
+  }
+}
+
+void tree_distance() {
+  dfs_down(0); cts++; dfs_up(0);
+}