diff --git a/algorithms/geometry/convex_hull.cpp b/algorithms/geometry/convex_hull.cpp
index 385259c66e44e2520cb68d83a786e347f15be681..1e29a4e6b56a815ac7a3227b6441372f83e7936c 100644
--- a/algorithms/geometry/convex_hull.cpp
+++ b/algorithms/geometry/convex_hull.cpp
@@ -3,40 +3,31 @@
 /// Time: O(n log n)
 /// Space: O(n)
 
-struct ConvexHull {
-  using point = pair<double,double>;
+using point = pair<double,double>;
 
-  // The three points are a counter-clockwise turn if 
-  // cross > 0, clockwise if cross < 0, and collinear 
-  // if cross = 0.
-  double cross(point a, point b, point c) {
-    return (b.fi - a.fi) * (c.se - a.se) - \
-      (b.se - a.se) * (c.fi - a.fi);
-  }
-
-  vector<int> run(const vector<point> &v) {
-    int k = 0;
-    vector<int> ans(v.size() * 2);
+bool cw(point a, point b, point c) {
+  return (b.fi - a.fi) * (c.se - a.se) - \
+         (b.se - a.se) * (c.fi - a.fi) < 0;
+}
 
-    sort(all(v), [](const point &a, const point &b) {
-      return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
-    });
+vector<point> convex_hull(vector<point> &v) {
+  int k = 0;
+  vector<point> ans(v.size() * 2);
 
-    // Uppermost part of convex hull
-    for (int i = 0; i < v.size(); ++i) {
-      while (k >= 2 && cross(v[ans[k-2]], v[ans[k-1]], v[i]) < 0)
-        k--;
-      ans[k++] = i;
-    }
+  sort(all(v), [](const point &a, const point &b) {
+    return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
+  });
 
-    // Lowermost part of convex hull
-    for (int i = v.size() - 2, t = k + 1; i >= 0; --i) {
-      while (k >= t && cross(v[ans[k-2]], v[ans[k-1]], v[i]) < 0)
-        k--;
-      ans[k++] = i;
-    }
+  for (int i = 0; i < v.size(); ++i) {
+    for (; k >= 2 && !cw(ans[k-2], ans[k-1], v[i]); --k);
+    ans[k++] = v[i];
+  }
 
-    ans.resize(k - 1);
-    return ans;
+  for (int i = v.size() - 2, t = k + 1; i >= 0; --i) {
+    for (; k >= t && !cw(ans[k-2], ans[k-1], v[i]); --k);
+    ans[k++] = v[i];
   }
-};
+
+  ans.resize(k - 1);
+  return ans;
+}
diff --git a/algorithms/geometry/geometry_functions.cpp b/algorithms/geometry/geometry_primitives.cpp
similarity index 99%
rename from algorithms/geometry/geometry_functions.cpp
rename to algorithms/geometry/geometry_primitives.cpp
index e1f78a1baec50000ac933e12ef02ce3973bca201..590ee0a744be0457d4daaffe7e7dd87357ac46ab 100644
--- a/algorithms/geometry/geometry_functions.cpp
+++ b/algorithms/geometry/geometry_primitives.cpp
@@ -1,4 +1,4 @@
-/// Geometry Functions
+/// Geometry Primitives
 
 #define to_deg(x) ((x * 180.0) / M_PI)
 #define to_rad(x) ((x * M_PI) / 180.0)
diff --git a/algorithms/structure/disjoint_set.cpp b/algorithms/structure/disjoint_set.cpp
index ad8de848fd81b870b7641510316a3c54a4aed654..aaa382322a3cac2e2ba534c69ba7f554e8af30d9 100644
--- a/algorithms/structure/disjoint_set.cpp
+++ b/algorithms/structure/disjoint_set.cpp
@@ -8,15 +8,15 @@
 
 struct DisjointSet {
   int N;
-  vector<int> rank, par;
+  vector<int> rnk, par;
 
   DisjointSet(int N) :
-    N(N), rank(N), par(N)
+    N(N), rnk(N), par(N)
   { init(); }
 
   void init() {
     iota(all(par), 0);
-    fill(all(rank), 0);
+    fill(all(rnk), 0);
   }
 
   int find_set(int x) {
@@ -29,10 +29,9 @@ struct DisjointSet {
     x = find_set(x);
     y = find_set(y);
 
-    if (x != y) {
-      if (rank[x] > rank[y]) swap(x, y);
-      if (rank[x] == rank[y]) rank[x]++;
-      par[x] = y;
-    }
+    if (x == y) return;
+    if (rnk[x] < rnk[y]) swap(x, y);
+    if (rnk[x] == rnk[y]) rnk[x]++;
+    par[y] = x;
   }
 };
diff --git a/algorithms/structure/lazy_segment_tree.cpp b/algorithms/structure/lazy_segment_tree.cpp
index 22f063faa672b45435f977e1a61222c2391cc04f..b3d95f7b24783f26f25bcce8820947fc55d02c1e 100644
--- a/algorithms/structure/lazy_segment_tree.cpp
+++ b/algorithms/structure/lazy_segment_tree.cpp
@@ -13,10 +13,15 @@ int N;
 
 template <typename T>
 struct LazySegmentTree {
+  using func = function<T(T,T)>;
+
+  T id;
+  func op;
   vector<T> tree, lazy;
 
-  LazySegmentTree(const vector<T> &v) : 
-    tree(MAX*4, 0), lazy(MAX*4, 0) 
+  LazySegmentTree(vector<T> &v, func op, T id=T()) : 
+    tree(MAX*4, 0), lazy(MAX*4, 0),
+    op(op), id(id)
   { build(v); }
 
   void build(const vector<T> &v, 
@@ -30,12 +35,12 @@ struct LazySegmentTree {
       int m = (l + r) / 2;
       build(v, left(node), l, m);
       build(v, right(node), m + 1, r);
-      tree[node] = tree[left(node)] + tree[right(node)];
+      tree[node] = op(tree[left(node)], tree[right(node)]);
     }
   }
 
   void push(int node, int l, int r, T val) {
-    tree[node] += (r - l + 1)*val;
+    tree[node] += (r - l + 1) * val;
 
     if (l != r) {
       lazy[left(node)] += val;
@@ -59,14 +64,14 @@ struct LazySegmentTree {
       int m = (l + r) / 2;
       update(i, j, val, left(node), l, m);
       update(i, j, val, right(node), m + 1, r);
-      tree[node] = tree[left(node)] + tree[right(node)];
+      tree[node] = op(tree[left(node)], tree[right(node)]);
     }
   }
 
   T query(int i, int j, 
       int node = 1, int l = 0, int r = N - 1)
   {
-    if (l > r || l > j || r < i) return 0;
+    if (l > r || l > j || r < i) return id;
 
     if (lazy[node])
       push(node, l, r, lazy[node]);
@@ -77,6 +82,6 @@ struct LazySegmentTree {
     int m = (l + r) / 2;
     T q1 = query(i, j, left(node), l, m);
     T q2 = query(i, j, right(node), m + 1, r);
-    return q1 + q2;
+    return op(q1, q2);
   }
 };
diff --git a/algorithms/structure/mo_algorithm.cpp b/algorithms/structure/mo_algorithm.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c174c545fdf5d7e38ff06789f388f2b8275922b5
--- /dev/null
+++ b/algorithms/structure/mo_algorithm.cpp
@@ -0,0 +1,42 @@
+/// Mo's Algorithm
+///
+/// Time: O((n + q) * sqrt{n})
+/// Space: O(n + q)
+
+struct Query {
+  int l, r, idx;
+};
+
+vector<int> mos_algorithm(vector<Query> Q) {
+  int blk_size = (int) sqrt(v.size() + 0.0) + 1;
+
+  vector<int> ans(Q.size());
+  sort(all(Q), [](Query a, Query b) {
+    return ii(a.l / blk_size, a.r) < ii(b.l / blk_size, b.r);
+  });
+
+  int curr_l = 0, curr_r = -1;
+
+  for (auto q : Q) {
+    while (curr_l > q.l) {
+      curr_l--;
+      add(curr_l);
+    }
+    while (curr_r < q.r) {
+      curr_r++;
+      add(curr_r);
+    }
+    while (curr_l < q.l) {
+      remove(curr_l);
+      curr_l++;
+    }
+    while (curr_r > q.r) {
+      remove(curr_r);
+      curr_r--;
+    }
+
+    ans[q.idx] = get_ans();
+  }
+
+  return ans;
+}
diff --git a/algorithms/structure/segment_tree.cpp b/algorithms/structure/segment_tree.cpp
index b2ee9399498df82219892276be3a859111d68ae4..c62f76d289f6816ae519d699fe4dbf062505b514 100644
--- a/algorithms/structure/segment_tree.cpp
+++ b/algorithms/structure/segment_tree.cpp
@@ -9,31 +9,30 @@
 ///   - Query returns $op([l,r))$
 ///   - Provide identity value if necessary (default is T())
 
-// Example: SegmentTree<int,plus<int>> seg(n)
-template <typename T, typename OT = T(*)(T&, T&)>
+template <typename T>
 struct SegmentTree {
+  using func = function<T(T,T)>;
+
+  T id;
   int N;
-  T ident;
-  OT op;
+  func op;
   vector<T> tree;
 
-  SegmentTree(int N, T id = T()) : 
-    N(N), ident(id), tree(2 * N, id) {}
+  SegmentTree(int N, func op, T id = T()) : 
+    N(N), op(op), id(id), tree(2*N, id) {}
 
   void update(int idx, T val) {
-    idx += N;
-    tree[idx] = val;
-    for (; idx > 1; idx >>= 1)
-      tree[idx >> 1] = op(tree[idx & ~1], tree[idx | 1]);
+    tree[idx + N] = val;
+    for (idx += N; idx > 1; idx/=2)
+      tree[idx/2] = op(tree[idx & ~1], tree[idx | 1]);
   }
 
   T query(int l, int r) {
-    T ra = ident, rb = ident;
-    l += N, r += N;
-    for (; l < r; l >>= 1, r >>= 1) {
-      if (l & 1) ra = op(ra, tree[l++]);
-      if (r & 1) rb = op(tree[--r], rb);
+    T ans = id;
+    for (l += N, r += N ; l < r; l/=2, r/=2) {
+      if (l & 1) ans = op(ans, tree[l++]);
+      if (r & 1) ans = op(ans, tree[--r]);
     }
-    return op(ra, rb);
+    return ans;
   }
 };
diff --git a/algorithms/structure/segment_tree_2d.cpp b/algorithms/structure/segment_tree_2d.cpp
index dbe716ba211a0d9df6a3ded2bc2a72e305fdb497..47818c79664425166e1a1210c867a07ddc6601be 100644
--- a/algorithms/structure/segment_tree_2d.cpp
+++ b/algorithms/structure/segment_tree_2d.cpp
@@ -16,13 +16,19 @@ int N, M;
 
 template<typename T>
 struct SegmentTree2D {
-  vector<vector<T>> tree;
+  using func = function<T(T,T)>;
+  using matrix<T> = vector<vector<T>>;
 
-  SegmentTree2D(const vector<vector<T>> &mat) :
-    tree(4*MAX, vector<T>(4*MAX, 0))
+  T id;
+  func op;
+  matrix<T> tree;
+
+  SegmentTree2D(matrix<T> &mat, func op, T id = T()) :
+    tree(4*MAX, vector<T>(4*MAX, 0)),
+    op(op), id(id)
   { build(mat); }
 
-  void build_row(const vector<vector<T>> &mat, 
+  void build_row(const matrix<T> &mat, 
       int ni, int li, int ri,
       int nj = 1, int lj = 0, int rj = M - 1)
   {
@@ -30,16 +36,16 @@ struct SegmentTree2D {
       if (li == ri) 
         tree[ni][nj] = mat[li][lj];
       else 
-        tree[ni][nj] = tree[left(ni)][nj] + tree[right(ni)][nj];
+        tree[ni][nj] = op(tree[left(ni)][nj], tree[right(ni)][nj]);
     } else {
       int m = (lj + rj) / 2;
       build_row(mat, ni, li, ri, left(nj), lj, m);
       build_row(mat, ni, li, ri, right(nj), m+1, rj);
-      tree[ni][nj] = tree[ni][left(nj)] + tree[ni][right(nj)];
+      tree[ni][nj] = op(tree[ni][left(nj)], tree[ni][right(nj)]);
     }
   }
 
-  void build(const vector<vector<T>> &mat,
+  void build(const matrix<T> &mat,
       int ni = 1, int li = 0, int ri = N - 1) 
   {
     if (li != ri) {
@@ -53,7 +59,7 @@ struct SegmentTree2D {
   T query_row(int j1, int j2, int i,
       int nj = 1, int lj = 0, int rj = M - 1) 
   {
-    if (lj > rj || lj > j2 || rj < j1) return 0;
+    if (lj > rj || lj > j2 || rj < j1) return id;
 
     if (j1 <= lj && rj <= j2)
       return tree[i][nj];
@@ -61,13 +67,13 @@ struct SegmentTree2D {
     int m = (lj + rj) / 2;
     T q1 = query_row(j1, j2, i, left(nj), lj, m);
     T q2 = query_row(j1, j2, i, right(nj), m + 1, rj);
-    return q1 + q2;
+    return op(q1, q2);
   }
 
   T query(int i1, int j1, int i2, int j2,
       int ni = 1, int li = 0, int ri = N - 1) 
   {
-    if (li > ri || li > i2 || ri < i1) return 0;
+    if (li > ri || li > i2 || ri < i1) return id;
 
     if (i1 <= li && ri <= i2)
       return query_row(j1, j2, ni);
@@ -75,7 +81,7 @@ struct SegmentTree2D {
     int m = (li + ri) / 2;
     T q1 = query(i1, j1, i2, j2, left(ni), li, m);
     T q2 = query(i1, j1, i2, j2, right(ni), m + 1, ri);
-    return q1 + q2;
+    return op(q1, q2);
   }
 
   void update_row(int i, int j, T val,
@@ -88,12 +94,12 @@ struct SegmentTree2D {
       if (li == ri) 
         tree[ni][nj] = val;
       else 
-        tree[ni][nj] = tree[left(ni)][nj] + tree[right(ni)][nj];
+        tree[ni][nj] = op(tree[left(ni)][nj], tree[right(ni)][nj]);
     } else {
       int m = (lj + rj) / 2;
       update_row(i, j, val, ni, li, ri, left(nj), lj, m);
       update_row(i, j, val, ni, li, ri, right(nj), m+1, rj);
-      tree[ni][nj] = tree[ni][left(nj)] + tree[ni][right(nj)];
+      tree[ni][nj] = op(tree[ni][left(nj)], tree[ni][right(nj)]);
     }
   }
 
diff --git a/algorithms/structure/sqrt_decomposition.cpp b/algorithms/structure/sqrt_decomposition.cpp
index 2defc34aa7ef7b0cfa44ceae21876f387b154104..b84d1a5e77a89cb2fa64eabfc9e39f1bd47e065e 100644
--- a/algorithms/structure/sqrt_decomposition.cpp
+++ b/algorithms/structure/sqrt_decomposition.cpp
@@ -7,46 +7,45 @@
 /// Space: O(n)
 
 struct SqrtDecomposition {
-  int block_size;
-  vector<int> v, block;
+  int blk_size;
+  vector<int> v, blk;
 
   SqrtDecomposition(vector<int> v) :
-    v(v), block(v.size())
+    v(v), blk(v.size())
   { init(); }
 
   void init() {
-    preprocess(v.size());
+    build();
   }
 
   void update(int idx, int val) {
-    block[idx / block_size] += val - v[idx];
+    blk[idx / blk_size] += val - v[idx];
     v[idx] = val;
   }
 
   int query(int l, int r) {
     int ans = 0;
-
-    for (; l < r && ((l % block_size) != 0); ++l)
-      ans += v[l];
-
-    for (; l + block_size <= r; l += block_size)
-      ans += block[l / block_size];
-
-    for (; l <= r; ++l)
-      ans += v[l];
+    int cl = l/blk_size, cr = r/blk_size;
+
+    if (cl == cr) {
+      for (int i = l; i <= r; ++i)
+        ans += v[i];
+    } else {
+      for (int i = l, end=(cl+1)*blk_size-1; i <= end; ++i)
+        ans += v[i];
+      for (int i = cl+1; i <= cr - 1; ++i)
+        ans += blk[i];
+      for (int i = cr*blk_size; i <= r; ++i)
+        ans += v[i];
+    }
 
     return ans;
   }
 
-  void preprocess(int n) {
-    block_size = sqrt(n);
-
-    int idx = -1;
-    for (int i = 0; i < n; ++i) {
-      if (i % block_size == 0)
-        block[++idx] = 0;
-
-      block[idx] += v[i];
-    }
+  void build() {
+    int n = v.size();
+    blk_size = (int) sqrt(n + 0.0) + 1;
+    for (int i = 0; i < n; ++i)
+      blk[idx / blk_size] += v[i];
   }
 };
diff --git a/caderno.pdf b/caderno.pdf
index fc4729e8045c647ef5f437a46b407711e31e7563..675ee1f62ca6a45f7a194cdd7ef6a0ce58523902 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/gen_notebook b/gen_notebook
index 3d13e4727fea35cc45bcc18f77f1282987acf2b0..a596a406e2ed5500eb6d91126908b755e5fafb97 100755
--- a/gen_notebook
+++ b/gen_notebook
@@ -18,6 +18,7 @@ else
     exit 1
   fi
 
+  echo
   echo "Generating PDF..."
 
   # Lualatex must be used in order to work with the correct font