diff --git a/algorithms/graph/dinic.cpp b/algorithms/graph/dinic.cpp
index e9fe5513f5da4d1b8647b92fa4d57cdfa56eb265..f45e94ff17c22c38c6ef17b5086aee75fa2f79b3 100644
--- a/algorithms/graph/dinic.cpp
+++ b/algorithms/graph/dinic.cpp
@@ -13,7 +13,9 @@ struct Dinic {
   vector<vector<Edge>> graph;
 
   Dinic(int N) : 
-    N(N), depth(N), start(N), graph(N) {}
+    N(N), depth(N), 
+    start(N), graph(N) 
+  {}
 
   void add_edge(int u, int v, int c) {
     Edge forw = { v, 0, c, (int) graph[v].size() };
diff --git a/algorithms/graph/ford_fulkerson.cpp b/algorithms/graph/ford_fulkerson.cpp
index 8562182dfc56136b23c454b8929676e018dec4a9..fb7a77f0ef01cacbe725a728affa4b2562fdd8c6 100644
--- a/algorithms/graph/ford_fulkerson.cpp
+++ b/algorithms/graph/ford_fulkerson.cpp
@@ -16,7 +16,9 @@ struct FordFulkerson {
     N(N), par(N), vis(N)
   { init(); }
 
-  void init() { fill(all(vis), 0); }
+  void init() {
+    fill(all(vis), 0);
+  }
 
   bool dfs(int s, int t) {
     vis[s] = true;
diff --git a/algorithms/graph/hopcroft_karp.cpp b/algorithms/graph/hopcroft_karp.cpp
index 542e9ac82ccec803d9e6628a4c8747b9f17b5b83..1897db3ab183c25add21a30561ea1b72cb04fffa 100644
--- a/algorithms/graph/hopcroft_karp.cpp
+++ b/algorithms/graph/hopcroft_karp.cpp
@@ -4,9 +4,10 @@
 /// Space: O(V + E)
 ///
 /// Caution: 
-///   - Assumes 1-indexed vertices in graph.
+///   - Assumes 0-indexed vertices in graph;
+///   - The vertex enumeration on the left CAN be the same as the right.
 ///
-/// Status: Tested (GCJ18-R2B)
+/// Status: Tested (GCJ18-R2C)
 
 vector<int> graph[MAX];
 
@@ -21,51 +22,56 @@ struct HopcroftKarp {
   { init(); }
 
   void init() {
-    fill(all(matchL), 0);
-    fill(all(matchR), 0);
+    fill(all(matchL), -1);
+    fill(all(matchR), -1);
   }
 
   bool bfs() {
     queue<int> Q;
-    for (int l = 1; l <= L; ++l)
-      if (matchL[l] == 0) {
+    for (int l = 0; l < L; ++l)
+      if (matchL[l] == -1) {
         dist[l] = 0;
         Q.push(l);
       } else
-        dist[l] = inf;
+        dist[l] = -1;
 
-    dist[0] = inf;
+    bool ans = false;
     while (!Q.empty()) {
       int l = Q.front(); Q.pop();
-      if (dist[l] < dist[0])
-        for (auto r : graph[l])
-          if (dist[matchR[r]] == inf) {
-            dist[matchR[r]] = dist[l] + 1;
-            Q.push(matchR[r]);
-          }
+      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 (dist[0] != inf);
+
+    return ans;
   }
 
   bool dfs(int l) {
-    if (l == 0) return true;
+    if (l == -1) 
+      return true;
+
     for (auto r : graph[l])
-      if (dist[matchR[r]] == dist[l] + 1)
+      if (matchR[r] == -1 || dist[matchR[r]] == dist[l] + 1)
         if (dfs(matchR[r])) {
           matchR[r] = l;
           matchL[l] = r;
           return true;
         }
-    dist[l] = inf;
+
     return false;
   }
 
   int run() {
     int ans = 0;
     while (bfs())
-      for (int l = 1; l <= L; ++l)
-        if (matchL[l] == 0 && dfs(l))
+      for (int l = 0; l < L; ++l)
+        if (matchL[l] == -1 && dfs(l))
           ans++;
+
     return ans;
   }
 };
diff --git a/algorithms/graph/kosaraju.cpp b/algorithms/graph/kosaraju.cpp
index dd9b98f5a8208c93709b1842fa69d70e6741e703..22a9f83b1e213fe9cb28ab4767f5a8489c563f05 100644
--- a/algorithms/graph/kosaraju.cpp
+++ b/algorithms/graph/kosaraju.cpp
@@ -15,7 +15,9 @@ struct Kosaraju {
     N(N), vis(N) 
   { init(); }
 
-  void init() { fill(all(vis), 0); }
+  void init() { 
+    fill(all(vis), 0); 
+  }
 
   void dfs(int x) {
     vis[x] = true;
@@ -35,7 +37,6 @@ struct Kosaraju {
 
   int run() {
     int scc = 0;
-    init();
     for (int i = 0; i < N; ++i)
       if (!vis[i])
         fill_stack(i);
@@ -55,6 +56,7 @@ struct Kosaraju {
         scc++;
       }
     }
+
     return scc;
   }
 };
diff --git a/algorithms/graph/min_cost_max_flow.cpp b/algorithms/graph/min_cost_max_flow.cpp
index 101ab2ca58de0e44bcf01741ba3d9a0aa9aa6f2f..c8dd2bb0f8e3ee6aca0538feee0626a58faae444 100644
--- a/algorithms/graph/min_cost_max_flow.cpp
+++ b/algorithms/graph/min_cost_max_flow.cpp
@@ -61,13 +61,16 @@ struct MinCostMaxFlow {
       int flow = inf;
       for (int i = t; i != s; i = par[i])
         flow = min(flow, edges[ind[i]].cap);
+
       for (int i = t; i != s; i = par[i]) {
         edges[ind[i]  ].cap -= flow;
         edges[ind[i]^1].cap += flow;
       }
+
       min_cost += flow * dist[t];
       max_flow += flow;
     }
+
     return ii(min_cost, max_flow);
   }
 };
diff --git a/algorithms/graph/prim.cpp b/algorithms/graph/prim.cpp
index 53c4f2253a46dd5713543a2649d43586370c6f36..cb3fc48d100e86149c9bbf2b466886c10c746752 100644
--- a/algorithms/graph/prim.cpp
+++ b/algorithms/graph/prim.cpp
@@ -37,6 +37,7 @@ struct Prim {
             pq.push(ii(-i.se, -i.fi));
       }
     }
+
     return ans;
   }
 };
diff --git a/algorithms/graph/steiner_tree.cpp b/algorithms/graph/steiner_tree.cpp
index 829ac259083f0ad338e4259549691147fa84c7fe..073407be2167208c0bd99bd626d9c2b23b02b0aa 100644
--- a/algorithms/graph/steiner_tree.cpp
+++ b/algorithms/graph/steiner_tree.cpp
@@ -3,11 +3,11 @@
 /// Description:
 ///   A (minimum) Steiner tree is a tree that, given a graph G and a set of
 /// terminal vertices T (inside the graph), connects all vertices in T using 
-/// other vertices in G if necessary, minimizing the sum of weights of the 
+/// other vertices in G if necessary, ans minimizes the sum of weights of the 
 /// included edges. \par
-///   The algorithm works by using dynamic programming, where dp[i][mask] 
+///   The algorithm uses dynamic programming, where dp[i][mask] 
 /// stores the value of a Steiner tree rooted at $i$ containing the terminal
-/// nodes represented by the bits in bitmask. The algorithm iterates over all
+/// nodes represented by the bits in $mask$. The algorithm iterates over all
 /// bitmasks, and, at each iteration $mask$, every pair of complementary subsets
 /// are tested and dp[i][mask] is updated with the value given by the 
 /// combination of both trees. Then, still at step $mask$, dp[j][mask] is 
diff --git a/algorithms/graph/topological_sort.cpp b/algorithms/graph/topological_sort.cpp
index dbaab2285e076034669fcc1f84ff0d21b04e17e1..95a73fe1aa6dea2019908765100be37645e80d45 100644
--- a/algorithms/graph/topological_sort.cpp
+++ b/algorithms/graph/topological_sort.cpp
@@ -14,7 +14,9 @@ struct TopologicalSort {
     N(N), vis(N) 
   { init(); }
 
-  void init() { fill(all(vis), 0); }
+  void init() {
+    fill(all(vis), 0);
+  }
 
   bool dfs(int x) {
     vis[x] = 1;
diff --git a/algorithms/graph/travelling_salesman.cpp b/algorithms/graph/travelling_salesman.cpp
index c4e1c08c709d32f720b192ecab2b48303f546157..c64dce724cfadcb211473478e8a871540890f63d 100644
--- a/algorithms/graph/travelling_salesman.cpp
+++ b/algorithms/graph/travelling_salesman.cpp
@@ -1,7 +1,7 @@
 /// Travelling Salesman
 ///
 /// Description:
-///   Given a graph and an origin vertex, this algorithm return the shortest
+///   Given a graph and an origin vertex, this algorithm returns the shortest
 /// possible route that visits each vertex and returns to the origin. \par
 ///   The algorithm works by using dynamic programming, where dp[i][mask]
 /// stores the last visited vertex $i$ and a set of visited vertices 
diff --git a/algorithms/math/pollard_rho.cpp b/algorithms/math/pollard_rho.cpp
index b520f3dd7615cb0dab1eb4b0ef8d981b6aa5e289..99239b17f187c00e82e23cbe001021dc1ad7a853 100644
--- a/algorithms/math/pollard_rho.cpp
+++ b/algorithms/math/pollard_rho.cpp
@@ -13,7 +13,7 @@ ll pollard(ll n) {
 
   if (n % 2 == 0) return 2;
 
-  for (ll i = 2;; ++i) {
+  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));
diff --git a/algorithms/string/aho_corasick.cpp b/algorithms/string/aho_corasick.cpp
index f5c29f2cf1c916493dabcb4f7a39af079a7f6b30..b6aaa36efb1d1677d6661a76380789f539c66f53 100644
--- a/algorithms/string/aho_corasick.cpp
+++ b/algorithms/string/aho_corasick.cpp
@@ -10,7 +10,6 @@
 /// Caution:
 ///   - Match might not find all occurences when repeated strings are given (fix with map)
 
-// *: Use only if "match_all" is necessary
 struct AhoCorasick {
   struct Node {
     vector<int> words;
diff --git a/algorithms/string/kmp.cpp b/algorithms/string/kmp.cpp
index 23581c22c7ed4c7bf164e092eb9da8dd818a9e09..85ff29fe4643394e09614081a7efae5d1d28e687 100644
--- a/algorithms/string/kmp.cpp
+++ b/algorithms/string/kmp.cpp
@@ -16,7 +16,7 @@ struct KMP {
   { preprocess(); }
 
   void preprocess() {
-    patt[0] = 0;
+    pi[0] = 0;
     for (int i = 1, j = 0; i < patt.size(); ++i) {
       while (j > 0 && patt[i] != patt[j]) 
         j = pi[j - 1];
diff --git a/algorithms/structure/hash_function.cpp b/algorithms/structure/hash_function.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4497b534301f69c8702ed2f259af88c328776a44
--- /dev/null
+++ b/algorithms/structure/hash_function.cpp
@@ -0,0 +1,28 @@
+/// Hash Function (splitmix64)
+///
+/// Description:
+///   The default hash function for unordered\_map in C++ is not reliable when
+/// it comes to non-random input (i.e. input designed to cause collisions, 
+/// such as multiples of a specific prime). This custom hash function solves 
+/// this problem (https://codeforces.com/blog/entry/62393).
+///
+/// Time:  O(1)
+/// Space: O(n)
+
+struct CustomHash {
+  static uint64_t splitmix64(uint64_t x) {
+    x += 0x9e3779b97f4a7c15;
+    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
+    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
+    return x ^ (x >> 31);
+  }
+
+  size_t operator()(uint64_t x) const {
+    static const uint64_t FIXED_RANDOM = chrono::steady_clock::now()
+      .time_since_epoch()
+      .count();
+    return splitmix64(x + FIXED_RANDOM);
+  }
+};
+
+unordered_map<ll,int,CustomHash> M;
diff --git a/algorithms/structure/sparse_table.cpp b/algorithms/structure/sparse_table.cpp
index 841f9ca24b3ca4a64f773e2377ea45a6860ef2b5..3d08456b08952ff570515a00e7a61e6e40c281a7 100644
--- a/algorithms/structure/sparse_table.cpp
+++ b/algorithms/structure/sparse_table.cpp
@@ -38,7 +38,7 @@ struct SparseTable {
         table[i][j] = func(table[i][j-1], table[i+(1<<(j-1))][j-1]);
   }
 
-  ll query(int l, int r) {
+  T query(int l, int r) {
     int j = log[r - l + 1];
     return func(table[l][j], table[r - (1<<j) + 1][j]);
   }
diff --git a/caderno.pdf b/caderno.pdf
index f671b4a0e7e53af116e9af61625c66aa25f4e51e..6f3e97c4cb78c2cd65a23c9b20a96dbf2f81cf99 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/notebook/gen_latex.py b/notebook/gen_latex.py
index 1474e8bafbc256fc504111ffce28e5056991ee99..4ef9259cb1ced819edb28aad3535d1cfed7053db 100644
--- a/notebook/gen_latex.py
+++ b/notebook/gen_latex.py
@@ -209,7 +209,9 @@ class LatexGenerator:
         self._write('\\tableofcontents\n')
         self._write('\\newpage\n\n')
 
+        self._write('\\begin{multicols*}{3}\n')
         self._gen_tree_latex(self.tree)
+        self._write('\\end{multicols*}\n')
 
         self._write('\\end{document}\n')
 
@@ -247,12 +249,12 @@ class LatexGenerator:
     # Generates LaTeX for entire tree recursively.
     def _gen_tree_latex(self, sub, path = '', depth = 0):
         if type(sub) == list:
-            self._write('\\begin{multicols}{' + self._multicol(path) + '}\n')
+            #self._write('\\begin{multicols*}{' + self._multicol(path) + '}\n')
             for i in sub:
                 source = self.SourceFile(path + i)
                 self._gen_title_latex(source.name, depth)
                 self._gen_code_latex(source)
-            self._write('\\end{multicols}\n')
+            #self._write('\\end{multicols*}\n')
         else:
             for i in sub:
                 self._gen_title_latex(self._parse_dir_name(i), depth)
diff --git a/notebook/header.tex b/notebook/header.tex
index 52335f0c892649b408556c04747b546d38ebae11..e705c1273350b123dcef556a4b3b33b0e1295056 100644
--- a/notebook/header.tex
+++ b/notebook/header.tex
@@ -38,8 +38,8 @@
     bottom=5mm,
 }
 
-% Set sizes for *[sub]section
-\titleformat*{\subsubsection}{\large\bfseries}
+% Set sizes for [*sub]section
+\titleformat*{\subsubsection}{\normalsize\bfseries}
 \titleformat*{\subsection}{\Large\bfseries}
 \titleformat*{\section}{\LARGE\bfseries}