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); +}