diff --git a/algorithms/graph/bellman_ford.cpp b/algorithms/graph/bellman_ford.cpp
index cb5674f01fe151fafa19f8026e1430377ec33eae..3a5b959760f3e52cad75a8c6e6b62641a15078f7 100644
--- a/algorithms/graph/bellman_ford.cpp
+++ b/algorithms/graph/bellman_ford.cpp
@@ -26,7 +26,6 @@ struct BellmanFord {
 
   int run(int s, int d) {
     dist[s] = 0;
-
     for (int i = 0; i < N; ++i)
       for (auto e : graph)
         if (dist[e.u] != inf && 
diff --git a/algorithms/graph/bipartite_match.cpp b/algorithms/graph/bipartite_match.cpp
index 53bf6120ae244888305a02412d6862e0ba631e1a..b29a9c8ede5da4de175bcd1caaa65bdb8257c1df 100644
--- a/algorithms/graph/bipartite_match.cpp
+++ b/algorithms/graph/bipartite_match.cpp
@@ -19,8 +19,7 @@ struct BipartiteMatching {
   }
 
   int dfs(int x) {
-    if (vis[x])
-      return 0;
+    if (vis[x]) return 0;
 
     vis[x] = 1;
     for (auto i : graph[x])
@@ -36,7 +35,6 @@ struct BipartiteMatching {
     int ans = 0;
     for (int i = 0; i < N; ++i)
       ans += dfs(i);
-
     return ans;
   }
 };
diff --git a/algorithms/graph/centroid_decomposition.cpp b/algorithms/graph/centroid_decomposition.cpp
index 8b0bd398343370945fc84b4efb28f7349c7da4ea..4701e866201e0dcc35139c173c06ba0a39839050 100644
--- a/algorithms/graph/centroid_decomposition.cpp
+++ b/algorithms/graph/centroid_decomposition.cpp
@@ -32,7 +32,6 @@ struct CentroidDecomposition {
   void build(int x, int p = -1) {
     int n = dfs(x);
     int c = get_centroid(x, n);
-
     vis[c] = 1;
     par[c] = p;
 
@@ -57,7 +56,5 @@ struct CentroidDecomposition {
     return x;
   }
 
-  int operator[](int i) {
-    return par[i];
-  }
+  int operator[](int i) { return par[i]; }
 };
diff --git a/algorithms/graph/dijkstra.cpp b/algorithms/graph/dijkstra.cpp
index 05cefc8c05a2e93e91f08a03aec3696a2a6b7768..ba7ec06081234b8d7659bedbd7f93a8d7a2a157b 100644
--- a/algorithms/graph/dijkstra.cpp
+++ b/algorithms/graph/dijkstra.cpp
@@ -26,7 +26,6 @@ struct Dijkstra {
 
   int run(int s, int d) {
     set<ii> pq;
-
     dist[s] = 0;
     pq.insert(ii(0, s));
 
diff --git a/algorithms/graph/dinic.cpp b/algorithms/graph/dinic.cpp
index fb65287d7ff7d164b87f978ee293830d9047dd3b..e9fe5513f5da4d1b8647b92fa4d57cdfa56eb265 100644
--- a/algorithms/graph/dinic.cpp
+++ b/algorithms/graph/dinic.cpp
@@ -31,27 +31,22 @@ struct Dinic {
 
     while (!Q.empty()) {
       int v = Q.front(); Q.pop();
-
       for (auto i : graph[v])
         if (depth[i.u] == -1 && i.f < i.c) {
           depth[i.u] = depth[v] + 1;
           Q.push(i.u);
         }
     }
-
     return depth[t] != -1;
   }
 
   int dfs(int s, int t, int f) {
-    if (s == t)
-      return f;
+    if (s == t) return f;
 
     for ( ; start[s] < graph[s].size(); ++start[s]) {
       Edge &e = graph[s][start[s]];
-
       if (depth[e.u] == depth[s] + 1 && e.f < e.c) {
         int min_f = dfs(e.u, t, min(f, e.c - e.f));
-
         if (min_f > 0) {
           e.f += min_f;
           graph[e.u][e.r].f -= min_f;
@@ -59,7 +54,6 @@ struct Dinic {
         }
       }
     }
-
     return 0;
   }
 
@@ -70,7 +64,6 @@ struct Dinic {
       while (int flow = dfs(s, t, inf))
         ans += flow;
     }
-
     return ans;
   }
 };
diff --git a/algorithms/graph/edmonds_karp.cpp b/algorithms/graph/edmonds_karp.cpp
index 4838a2bc755b19ea36d07f4d25d4d36c5c884270..f8e628e9597b355f1eabd63c4646f9a7ec95307f 100644
--- a/algorithms/graph/edmonds_karp.cpp
+++ b/algorithms/graph/edmonds_karp.cpp
@@ -27,10 +27,7 @@ struct EdmondsKarp {
 
     while (!Q.empty()) {
       int u = Q.front(); Q.pop();
-
-      if (u == t)
-        return true;
-
+      if (u == t) return true;
       for (int i = 0; i < N; ++i)
         if (!vis[i] && rg[u][i]) {
           vis[i] = true;
@@ -38,14 +35,12 @@ struct EdmondsKarp {
           Q.push(i);
         }
     }
-
     return false;
   }
 
   int run(int s, int t) {
     int ans = 0;
     par[s] = -1;
-
     memcpy(rg, graph, sizeof(graph));
 
     while (bfs(s, t)) {
@@ -57,11 +52,9 @@ struct EdmondsKarp {
         rg[par[i]][i] -= flow;
         rg[i][par[i]] += flow;
       }
-
       ans += flow;
       init();
     }
-
     return ans;
   }
 };
diff --git a/algorithms/graph/ford_fulkerson.cpp b/algorithms/graph/ford_fulkerson.cpp
index e49ae1281d16857f9bc8ac959af26a1fed9ca33b..8562182dfc56136b23c454b8929676e018dec4a9 100644
--- a/algorithms/graph/ford_fulkerson.cpp
+++ b/algorithms/graph/ford_fulkerson.cpp
@@ -20,24 +20,19 @@ struct FordFulkerson {
 
   bool dfs(int s, int t) {
     vis[s] = true;
-    if (s == t)
-      return true;
+    if (s == t) return true;
 
     for (int i = 0; i < N; ++i)
       if (!vis[i] && rg[s][i]) {
         par[i] = s;
-
-        if (dfs(i, t)) 
-          return true;
+        if (dfs(i, t)) return true;
       }
-
     return false;
   }
 
   int run(int s, int t) {
     int ans = 0;
     par[s] = -1;
-
     memcpy(rg, graph, sizeof(graph));
 
     while (dfs(s, t)) {
@@ -49,11 +44,9 @@ struct FordFulkerson {
         rg[par[i]][i] -= flow;
         rg[i][par[i]] += flow;
       }
-
       ans += flow;
       init();
     }
-
     return ans;
   }
 };
diff --git a/algorithms/graph/hld.cpp b/algorithms/graph/hld.cpp
index 2d9f871a0947fd4ce43eef80189a2deb72cc0f2f..d8fe4269cdf1a484293fa7e7a177983e9ec2420b 100644
--- a/algorithms/graph/hld.cpp
+++ b/algorithms/graph/hld.cpp
@@ -47,7 +47,6 @@ struct HLD {
     head(n), heavy(n, -1), pos(n), bot(n)
   {
     cnum = ptr = 0;
- 
     N = n; // global N for segtree
     dfs(0);
     decompose(0);
@@ -102,8 +101,7 @@ struct HLD {
       ans = seg.func(ans, seg.query(pos[head[b]], pos[b]));
     }
 
-    if (dep[a] > dep[b])
-      swap(a, b);
+    if (dep[a] > dep[b]) swap(a, b);
 
     // Remove "+ 1" when values are associated with vertices
     return seg.func(ans, seg.query(pos[a] + 1, pos[b]));
diff --git a/algorithms/graph/hopcroft_karp.cpp b/algorithms/graph/hopcroft_karp.cpp
index 2f74606cf746cf772c4b6a9aace8e9b0538a3200..542e9ac82ccec803d9e6628a4c8747b9f17b5b83 100644
--- a/algorithms/graph/hopcroft_karp.cpp
+++ b/algorithms/graph/hopcroft_karp.cpp
@@ -27,7 +27,6 @@ struct HopcroftKarp {
 
   bool bfs() {
     queue<int> Q;
-
     for (int l = 1; l <= L; ++l)
       if (matchL[l] == 0) {
         dist[l] = 0;
@@ -38,7 +37,6 @@ struct HopcroftKarp {
     dist[0] = inf;
     while (!Q.empty()) {
       int l = Q.front(); Q.pop();
-
       if (dist[l] < dist[0])
         for (auto r : graph[l])
           if (dist[matchR[r]] == inf) {
@@ -46,14 +44,11 @@ struct HopcroftKarp {
             Q.push(matchR[r]);
           }
     }
-
     return (dist[0] != inf);
   }
 
   bool dfs(int l) {
-    if (l == 0)
-      return true;
-
+    if (l == 0) return true;
     for (auto r : graph[l])
       if (dist[matchR[r]] == dist[l] + 1)
         if (dfs(matchR[r])) {
@@ -61,19 +56,16 @@ struct HopcroftKarp {
           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))
           ans++;
-
     return ans;
   }
 };
diff --git a/algorithms/graph/kosaraju.cpp b/algorithms/graph/kosaraju.cpp
index 209f95608ad5cdf8a579199092a549b8248b098b..dd9b98f5a8208c93709b1842fa69d70e6741e703 100644
--- a/algorithms/graph/kosaraju.cpp
+++ b/algorithms/graph/kosaraju.cpp
@@ -19,7 +19,6 @@ struct Kosaraju {
 
   void dfs(int x) {
     vis[x] = true;
-
     for (auto i : transp[x])
       if (!vis[i])
         dfs(i);
@@ -28,17 +27,14 @@ struct Kosaraju {
   // Fills stack with DFS starting points to find SCC.
   void fill_stack(int x) {
     vis[x] = true;
-
     for (auto i : graph[x])
       if (!vis[i])
         fill_stack(i);
-
     S.push(x);
   }
 
   int run() {
     int scc = 0;
-
     init();
     for (int i = 0; i < N; ++i)
       if (!vis[i])
@@ -48,20 +44,17 @@ struct Kosaraju {
     for (int i = 0; i < N; ++i)
       for (auto j : graph[i])
         transp[j].push_back(i);
-
     init();
 
     // Count SCC
     while (!S.empty()) {
       int v = S.top();
       S.pop();
-
       if (!vis[v]) {
         dfs(v);
         scc++;
       }
     }
-
     return scc;
   }
 };
diff --git a/algorithms/graph/lca.cpp b/algorithms/graph/lca.cpp
index 2c5da885748122ff831226178cad19180838ac1b..0a6311a55d986fb8ca368e61aa99cde395dc67c6 100644
--- a/algorithms/graph/lca.cpp
+++ b/algorithms/graph/lca.cpp
@@ -17,35 +17,34 @@
 ///   - query:      O(log V)
 /// Space: O(V + E + V log V)
 
-#define LOG 20 // log2(MAX)
+#define LOG 20
+#define COST 0
 
 vector<ii> graph[MAX];
 int par[MAX][LOG], cost[MAX][LOG];
 
-template <class F = function<T(const T&, const &T)>>
+template <typename T, class F = function<T(T,T)>>
 struct LCA {
   F func;
   vector<int> h;
 
-  LCA(int N, F &func) : h(N), func(func)
+  LCA(int N, F func) : h(N), func(func)
   { init(); }
 
   void init() {
     mset(par, -1);
     mset(cost, 0);
-    dfs(0); // root is 0
+    dfs(0);
   }
 
   void dfs(int v, int p = -1, int c = 0) {
     par[v][0] = p;
     cost[v][0] = c;
-
-    if (p != -1)
-      h[v] = h[p] + 1;
+    if (p != -1) h[v] = h[p] + 1;
 
     for (int i = 1; i < LOG; ++i)
-      if (par[v][i - 1] != -1) {
-        par[v][i] = par[par[v][i - 1]][i - 1];
+      if (par[v][i-1] != -1) {
+        par[v][i] = par[par[v][i-1]][i-1];
         cost[v][i] = func(cost[v][i], func(cost[v][i-1],
               cost[par[v][i-1]][i-1]));
       }
@@ -57,9 +56,7 @@ struct LCA {
 
   int query(int a, int b) {
     int ans = 0;
-
-    if (h[a] < h[b])
-      swap(a, b);
+    if (h[a] < h[b]) swap(a, b);
 
     for (int i = LOG - 1; i >= 0; --i)
       if (par[a][i] != -1 && h[par[a][i]] >= h[b]) {
diff --git a/algorithms/graph/min_cost_max_flow.cpp b/algorithms/graph/min_cost_max_flow.cpp
index 60092b1af5ab53cedfcade45a635b7c5acafe0be..101ab2ca58de0e44bcf01741ba3d9a0aa9aa6f2f 100644
--- a/algorithms/graph/min_cost_max_flow.cpp
+++ b/algorithms/graph/min_cost_max_flow.cpp
@@ -18,7 +18,6 @@ struct MinCostMaxFlow {
   void add_edge(int u, int v, int cap, int cost) {
     adj[u].pb(edges.size());
     edges.pb({ u, v, cap, cost });
-
     adj[v].pb(edges.size());
     edges.pb({ v, u, 0, -cost });
   }
@@ -28,7 +27,6 @@ struct MinCostMaxFlow {
   bool spfa(int s, int t) {
     fill(all(dist), inf);
     dist[s] = 0;
-
     queue<int> Q;
     Q.push(s);
 
@@ -39,7 +37,6 @@ struct MinCostMaxFlow {
       for (auto i : adj[u]) {
         Edge &e = edges[i];
         int v = e.v;
-
         if (e.cap > 0 && dist[v] > dist[u] + e.cost) {
           dist[v] = dist[u] + e.cost;
           par[v] = u;
@@ -52,7 +49,6 @@ struct MinCostMaxFlow {
         }
       }
     }
-
     return dist[t] < inf;
   }
 
@@ -65,16 +61,13 @@ 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 c4ec5b9e37a1a4446a8db3180e9cf98701510ed9..53c4f2253a46dd5713543a2649d43586370c6f36 100644
--- a/algorithms/graph/prim.cpp
+++ b/algorithms/graph/prim.cpp
@@ -19,7 +19,6 @@ struct Prim {
 
   int run() {
     vis[0] = true;
-
     priority_queue<ii> pq;
     for (auto i : graph[0])
       pq.push(ii(-i.se, -i.fi));
@@ -33,13 +32,11 @@ struct Prim {
       if (!vis[u]) {
         ans += w;
         vis[u] = true;
-
         for (auto i : graph[u])
           if (!vis[i.fi])
             pq.push(ii(-i.se, -i.fi));
       }
     }
-
     return ans;
   }
 };
diff --git a/algorithms/graph/tarjan.cpp b/algorithms/graph/tarjan.cpp
index ecd8f88f953323c0e764ef0cea221e65deaae637..09741dcfd29355fad621d840e99c2fb07be6abbf 100644
--- a/algorithms/graph/tarjan.cpp
+++ b/algorithms/graph/tarjan.cpp
@@ -24,7 +24,6 @@ struct Tarjan {
   void dfs(int x) {
     id[x] = low[x] = ind++;
     vis[x] = 1;
-
     S.push(x);
 
     for (auto i : graph[x])
@@ -37,13 +36,11 @@ struct Tarjan {
     // A SCC was found
     if (low[x] == id[x]) {
       int w;
-
       do {
         w = S.top(); S.pop();
         vis[w] = 0;
         scc[ncomp].pb(w);
       } while (w != x);
-
       ncomp++;
     }
   }
@@ -51,7 +48,6 @@ struct Tarjan {
   int run() {
     init();
     ncomp = ind = 0;
-
     for (int i = 0; i < N; ++i)
       scc[i].clear();
 
@@ -59,7 +55,6 @@ struct Tarjan {
     for (int i = 0; i < N; ++i)
       if (id[i] == -1)
         dfs(i);
-
     return ncomp;
   }
 };
diff --git a/algorithms/graph/topological_sort.cpp b/algorithms/graph/topological_sort.cpp
index 43ae3e7721afd5ecb1be1c9229cfbf1a6f335829..dbaab2285e076034669fcc1f84ff0d21b04e17e1 100644
--- a/algorithms/graph/topological_sort.cpp
+++ b/algorithms/graph/topological_sort.cpp
@@ -18,7 +18,6 @@ struct TopologicalSort {
 
   bool dfs(int x) {
     vis[x] = 1;
-
     for (auto i : graph[x]) {
       if (vis[i] == 1) return true;
       if (!vis[i] && dfs(i)) return true;
@@ -26,7 +25,6 @@ struct TopologicalSort {
 
     vis[x] = 2;
     S.push(x);
-
     return false;
   }
 
@@ -34,20 +32,16 @@ struct TopologicalSort {
   // or not.
   bool run(vector<int> &tsort) {
     init();
-
     bool cycle = false;
     for (int i = 0; i < N; ++i)
       if (!vis[i])
         cycle |= dfs(i);
-
-    if (cycle)
-      return true;
+    if (cycle) return true;
 
     while (!S.empty()) {
       tsort.pb(S.top());
       S.pop();
     }
-
     return false;
   }
 };
diff --git a/algorithms/graph/travelling_salesman.cpp b/algorithms/graph/travelling_salesman.cpp
index 3aebcc10d488cb6e8a5f9364ee571d02c8c32a22..c4e1c08c709d32f720b192ecab2b48303f546157 100644
--- a/algorithms/graph/travelling_salesman.cpp
+++ b/algorithms/graph/travelling_salesman.cpp
@@ -28,7 +28,6 @@ struct TSP {
   int solve(int i, int mask) {
     if (mask == (1 << N) - 1)
       return graph[i][0];
-
     if (dp[i][mask] != -1)
       return dp[i][mask];
 
@@ -37,7 +36,6 @@ struct TSP {
       if (!(mask & (1 << j)) && (i != j))
         ans = min(ans, graph[i][j] + 
             solve(j, mask | (1 << j)));
-
     return dp[i][mask] = ans;
   }
 
diff --git a/algorithms/math/binary_exponentiation.cpp b/algorithms/math/binary_exponentiation.cpp
index 818f7dd00075b8ae22fcc1fbe49ab939ea960e80..7c46c08136accebc42eea27cf310b5be11c77337 100644
--- a/algorithms/math/binary_exponentiation.cpp
+++ b/algorithms/math/binary_exponentiation.cpp
@@ -6,7 +6,7 @@
 /// that no overflow will occur when multiplying two large integers. It is
 /// definitely required in order to work with Miller-Rabin and Pollard's
 /// Rho implementations (when dealing with numbers that might go up to 
-/// $10^{18}$.
+/// $10^{18}$. USE BIN\_MUL ONLY IF NECESSARY (VERY SLOW).
 ///
 /// Time: O(log n)
 /// Space: O(1)
diff --git a/algorithms/math/euler_totient.cpp b/algorithms/math/euler_totient.cpp
index 83cf51db771176dea253c75eb1e2334035bac1a9..6f407b919f224076db30a048c272125bba915ae0 100644
--- a/algorithms/math/euler_totient.cpp
+++ b/algorithms/math/euler_totient.cpp
@@ -3,17 +3,17 @@
 /// Time: O(sqrt{n})
 /// Space: O(1)
 
-int phi(int n) {
-  int result = n;
+ll phi(ll n) {
+  ll ans = n;
 
-  for (int i = 2; i*i <= n; i++)
+  for (ll i = 2; i*i <= n; i++)
     if (n % i == 0) {
       while (n % i == 0) n /= i;
-      result -= result / i;
+      ans -= ans / i;
     }
 
   if (n > 1)
-    result -= (result / n);
+    ans -= (ans / n);
 
-  return result;
+  return ans;
 }
diff --git a/algorithms/structure/segment_tree.cpp b/algorithms/structure/segment_tree.cpp
index 7ef42b0cd743ae2e17b1c0173be268c6f348a8b5..9f388480225a16fbb50725b5d287dcc3b6ac96fd 100644
--- a/algorithms/structure/segment_tree.cpp
+++ b/algorithms/structure/segment_tree.cpp
@@ -6,66 +6,38 @@
 /// Space: O(n)
 ///
 /// Caution:
-///   - Provide value for N before any operation
 ///   - Provide identity value if necessary (default is T())
 
-#define left(x) (x << 1)
-#define right(x) ((x << 1) + 1)
-
-int N;
-
-template <typename T, class F = function<T(const T&, const T&)>>
+template<typename T, class F = function<T(T,T)>>
 struct SegmentTree {
+  int N;
   F func;
-  T ident = T();
+  T id = T();
   vector<T> tree;
 
-  SegmentTree(F func) : func(func), tree(MAX*4) {}
-
-  void build(const vector<T> &v, 
-      int node = 1, int l = 0, int r = N - 1) 
-  {
-    if (l > r) 
-      return;
+  SegmentTree(int N, F func) : 
+    N(N), func(func), tree(N*2, id) 
+  {}
 
-    if (l == r)
-      tree[node] = v[l];
-    else {
-      int m = (l + r) / 2;
-      build(v, left(node), l, m);
-      build(v, right(node), m + 1, r);
-      tree[node] = func(tree[left(node)], tree[right(node)]);
-    }
+  void build(const vector<T> &v) {
+    for (int i = 0; i < N; ++i)
+      tree[N + i] = v[i];
+    for (int i = N - 1; i > 0; --i) 
+      tree[i] = func(tree[i*2], tree[i*2+1]);
   }
 
-  void update(int i, T val, 
-      int node = 1, int l = 0, int r = N - 1) 
-  {
-    if (l > r || l > i || r < i) 
-      return;
-
-    if (l == r)
-      tree[node] = val;
-    else {
-      int m = (l + r) / 2;
-      update(i, val, left(node), l, m);
-      update(i, val, right(node), m + 1, r);
-      tree[node] = func(tree[left(node)], tree[right(node)]);
-    }
+  void update(int i, T x) {
+    tree[i += N] = x;
+    for (i /= 2; i > 0; i /= 2)
+      tree[i] = func(tree[i*2], tree[i*2+1]);
   }
 
-  T query(int i, int j, 
-      int node = 1, int l = 0, int r = N - 1)
-  {
-    if (l > r || l > j || r < i) 
-      return ident;
-
-    if (l >= i && r <= j)
-      return tree[node];
-
-    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 func(q1, q2);
+  T query(int i, int j) {
+    T left = id, right = id;
+    for (i += N, j += N; i < j; i /= 2, j /= 2) {
+      if (i & 1) left = func(left, tree[i++]);
+      if (j & 1) right = func(right, tree[--j]);
+    }
+    return func(left, right);
   }
 };
diff --git a/algorithms/structure/segment_tree_2d.cpp b/algorithms/structure/segment_tree_2d.cpp
index c39c43711a246ab177bca506c8416143c80fe00c..e749c57e0b114de4e0d3af5ba05ddde7b8681596 100644
--- a/algorithms/structure/segment_tree_2d.cpp
+++ b/algorithms/structure/segment_tree_2d.cpp
@@ -14,7 +14,7 @@
 
 int N, M;
 
-template<typename T, class F = function<T(const T&, const T&)>>
+template<typename T, class F = function<T(T,T)>>
 struct SegmentTree2D {
   using matrix<T> = vector<vector<T>>;
 
diff --git a/algorithms/structure/sparse_table.cpp b/algorithms/structure/sparse_table.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..841f9ca24b3ca4a64f773e2377ea45a6860ef2b5
--- /dev/null
+++ b/algorithms/structure/sparse_table.cpp
@@ -0,0 +1,45 @@
+/// Sparse Table
+///
+/// Time:
+///   - preprocess:  O(n log n)
+///   - query:  O(1)
+/// Space: O(n log n)
+///
+/// Caution:
+///   - func must be min, max, gcd, or lcm
+///   - Query computes for [l,r]
+
+#define LOG 20
+
+template <typename T, class F = function<T(T,T)>>
+struct SparseTable {
+  F func;
+  int N;
+  vector<T> log;
+  vector<vector<T>> table;
+
+  SparseTable(const vector<T> &v, F func) :
+    N(v.size()),
+    log(N + 1), 
+    table(N, vector<T>(LOG+1)), 
+    func(func)
+  { preprocess(v); }
+
+  void preprocess(const vector<T> &v) {
+    log[1] = 0;
+    for (int i = 2; i <= N; ++i)
+      log[i] = log[i >> 1] + 1;
+
+    for (int i = 0; i < N; ++i)
+      table[i][0] = v[i];
+
+    for (int j = 1; j <= LOG; ++j)
+      for (int i = 0; i + (1 << j) <= N; ++i)
+        table[i][j] = func(table[i][j-1], table[i+(1<<(j-1))][j-1]);
+  }
+
+  ll 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 fd8c3722363caf575817cd20de9fc44fbba2ee86..f671b4a0e7e53af116e9af61625c66aa25f4e51e 100644
Binary files a/caderno.pdf and b/caderno.pdf differ
diff --git a/contests/Cadernaveis/URI1130.cpp b/contests/Cadernaveis/URI1130.cpp
index 012bed61b5dc04d6e6a1efc0f9c79de8852f8688..3b235dd6d4e203de06fd92f7d652a434898e19e2 100644
--- a/contests/Cadernaveis/URI1130.cpp
+++ b/contests/Cadernaveis/URI1130.cpp
@@ -23,25 +23,21 @@ using ll = long long;
 using ii = pair<int,int>;
 
 int dp[MAX];
-//int foi[MAX];
 
 int solve(int n) {
-  if (n < 5) 
-    return 0;
-  if (dp[n] != -1)
-    return dp[n];
-
+  if (n < 5) return 0;
+  if (dp[n] != -1) return dp[n];
+  
   vector<int> foi(MAX, 0);
-  for (int j = 2; j < n - 2; ++j)
-    foi[solve(j) ^ solve(n - 1 - j)] = 1;
+  for (int i = 2; i < n - 2; ++i)
+    foi[solve(i) ^ solve(n - i - 1)] = 1;
 
-  for (int j = 0; j < MAX; ++j)
-    if (!foi[j]) {
-      dp[n] = j;
-      break;
-    }
+  for (int i = 0; i < MAX; ++i)
+    if (!foi[i]) 
+      return dp[n] = i;
 
-  return dp[n];
+  assert(false);
+  return -1;
 }
 
 int main() {
@@ -53,28 +49,29 @@ int main() {
   while (cin >> n && n) {
     string s; cin >> s;
 
-    bool done = false;
-    for (int i = 1; i < n; ++i)
-      if (s[i] == 'X' && s[i-1] == 'X') done = true;
-    for (int i = 2; i < n; ++i)
-      if (s[i] == 'X' && s[i-2] == 'X') done = true;
+    bool poss = false;
+    for (int i = 0; i < n - 1; ++i)
+      poss |= (s[i] == 'X' && s[i+1] == 'X');
+    for (int i = 0; i < n - 2; ++i)
+      poss |= (s[i] == 'X' && s[i+2] == 'X');
 
-    if (done) {
+    if (poss) {
       cout << 'S' << ende;
       continue;
     }
 
-    int ans = 0;
-    int last = -3;
-    for (int i = 0; i < n; ++i) {
+    int last = -1, ans = 0;
+    for (int i = 0; i < n; ++i)
       if (s[i] == 'X') {
-        ans ^= solve(i-last-1);
+        if (last == -1) ans ^= solve(2 + i);
+        else ans ^= solve(i - last - 1);
         last = i;
       }
-    }
 
-    ans ^= solve(n-last+1);
-    cout << (ans ? 'S' : 'N') << endl;
+    if (last == -1) ans ^= solve(2 + n + 2);
+    else ans ^= solve((n - last - 1) + 2);
+
+    cout << (ans ? 'S' : 'N') << ende;
   }
 
   return 0;
diff --git a/contests/ICPC_LA14/A.cpp b/contests/ICPC_LA14/A.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0a3af82c230e6270f137d36eb87f832933038a03
--- /dev/null
+++ b/contests/ICPC_LA14/A.cpp
@@ -0,0 +1,37 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  bool poss = true;
+  vector<int> v(5);
+  for (auto &i : v) cin >> i;
+  for (auto &i : v) {
+    int x; cin >> x;
+    if (x + i != 1)
+      poss = false;
+  }
+
+  cout << (poss ? "Y" : "N") << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA14/B.cpp b/contests/ICPC_LA14/B.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..106696f79ccdfd17412a1823986a5d070e5818b1
--- /dev/null
+++ b/contests/ICPC_LA14/B.cpp
@@ -0,0 +1,47 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  ll a, b; cin >> a >> b;
+  string s; cin >> s;
+  int n = s.size();
+
+  int fst = n - 1;
+  auto update = [&]() {
+    while (fst >= 0 && s[fst] == 'W') fst--;
+  };
+
+  update();
+  ll ans = 0;
+  for (int i = 0; i < n; ++i) {
+    if (s[i] == 'W' && i < fst) {
+      ans += min((fst - i) * (a - b), a);
+      swap(s[fst], s[i]);
+      update();
+    }
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA14/C.cpp b/contests/ICPC_LA14/C.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2f74bb04b579c732b5f8cf8324892fb63a52876e
--- /dev/null
+++ b/contests/ICPC_LA14/C.cpp
@@ -0,0 +1,72 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  string s; cin >> s;
+  int n = s.size();
+  bool ne = true;
+  vector<string> v;
+  for (int i = 0; i < n; ++i)
+    if (s[i] >= '0' && s[i] <= '9') {
+      if (ne) {
+        v.pb("");
+        ne = false;
+      }
+      v.back().pb(s[i]);
+    } else
+      ne = true;
+
+
+  ll ans = 0;
+  vector<int> md(3, 0);
+  for (const auto &i : v) {
+    int sum = 0;
+    for (int j = 0; j < i.size(); ++j) {
+      sum += i[j] - '0';
+      md[sum % 3]++;
+    }
+
+    for (int j = 0; j < i.size(); ++j) {
+      ans += md[0];
+      if ((i[j] - '0') % 3 == 2) {
+        md[2]--;
+        int aux = md[0];
+        md[0] = md[2];
+        md[2] = md[1]; 
+        md[1] = aux;
+      } else if ((i[j] - '0') % 3 == 1) {
+        md[1]--;
+        int aux = md[1];
+        md[1] = md[2];
+        md[2] = md[0];
+        md[0] = aux;
+      } else {
+        md[0]--;
+      }
+    }
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA14/H.cpp b/contests/ICPC_LA14/H.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2ec7beb94810da3b7ea7b8c605b46e0e3e53dac9
--- /dev/null
+++ b/contests/ICPC_LA14/H.cpp
@@ -0,0 +1,39 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+  
+  int n; cin >> n;
+  vector<int> v(n);
+  for (auto &i : v) cin >> i;
+  sort(all(v));
+
+  int sum1 = 0, sum2 = 0;
+  for (int i = 0; i < n; i+=2)
+    sum1 += min(abs(v[i] - v[(i+1)%n]), 24 - abs(v[i] - v[(i+1)%n]));
+  for (int i = 0; i < n - 1; i+=2)
+    sum2 += min(abs(v[i] - v[(i-1+n)%n]), 24 - abs(v[i] - v[(i-1+n)%n]));
+
+  cout << min(sum1, sum2) << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA14/I.cpp b/contests/ICPC_LA14/I.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fd8cd6ad022aa271792c927afe9d7b070e7fc665
--- /dev/null
+++ b/contests/ICPC_LA14/I.cpp
@@ -0,0 +1,68 @@
+#include <bits/stdc++.h>
+
+#define MAX 101010
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int fri[MAX];
+int tem[MAX];
+vector<ii> graph[MAX];
+
+void pre(int x, int p = -1) {
+  tem[x] = fri[x];
+  for (auto i : graph[x])
+    if (i.fi != p) {
+      pre(i.fi, x);
+      tem[x] += tem[i.fi];
+    }
+}
+
+ii solve(int x, int p = -1) {
+  ii ans{0, 0};
+  for (auto i : graph[x])
+    if (i.fi != p && tem[i.fi]) {
+      ii a = solve(i.fi, x);
+      ans.fi = max(ans.fi, a.fi + i.se);
+      ans.se += a.se + i.se;
+    }
+
+  return ans;
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, f; cin >> n >> f;
+  for (int i = 0; i < n - 1; ++i) {
+    int a, b, c; cin >> a >> b >> c; a--, b--;
+    graph[a].pb(ii(b, c));
+    graph[b].pb(ii(a, c));
+  }
+
+  for (int i = 0; i < f; ++i) {
+    int x; cin >> x; x--;
+    fri[x] = 1;
+  }
+
+  pre(0);
+  ii ans = solve(0);
+  cout << ans.se - ans.fi << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA14/a.out b/contests/ICPC_LA14/a.out
new file mode 100755
index 0000000000000000000000000000000000000000..b54c423916156b4c43666b5a1283af2eecc57bdc
Binary files /dev/null and b/contests/ICPC_LA14/a.out differ
diff --git a/contests/ICPC_LA19/E.cpp b/contests/ICPC_LA19/E.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..70612c0d8d3060bde1157a27db2f906de632b08e
--- /dev/null
+++ b/contests/ICPC_LA19/E.cpp
@@ -0,0 +1,43 @@
+/// E. Eggfruit Cake
+
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  string s; cin >> s; s += s;
+  int x; cin >> x;
+  int n = s.size();
+
+  vector<int> last(n);
+  last[n-1] = (s[n-1] == 'E') ? n - 1 : inf;
+  for (int i = n - 2; i >= 0; --i)
+    last[i] = (s[i] == 'E') ? i : last[i+1];
+
+  ll ans = 0LL;
+  for (int i = 0; i < n/2; ++i)
+    ans += max(0, x - (last[i] - i));
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA19/I.cpp b/contests/ICPC_LA19/I.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b493ad468acf6d7dc8614104aae83a0fbacad978
--- /dev/null
+++ b/contests/ICPC_LA19/I.cpp
@@ -0,0 +1,55 @@
+/// I. Improve SPAM
+
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int dp[2010], foi[2010];
+vector<int> graph[2010];
+
+ll solve(int x, int l) {
+  if (x >= l) return foi[x] = 1;
+  if (dp[x] != -1) return dp[x];
+
+  ll ans = 0;
+  for (auto i : graph[x])
+    ans = (ans + solve(i, l)) % MOD;
+  return dp[x] = ans;
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, l; cin >> n >> l;
+  for (int i = 0; i < l; ++i) {
+    int k; cin >> k;
+    for (int j = 0; j < k; ++j) {
+      int x; cin >> x; x--;
+      graph[i].pb(x);
+    }
+  }
+
+  mset(dp, -1);
+  ll b = solve(0, l);
+  ll a = accumulate(foi + l, foi + 2010, 0);
+  cout << b << " " << a << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA19/K.cpp b/contests/ICPC_LA19/K.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f3f19ae6dccd98f3a744f66f748255f72be39d2
--- /dev/null
+++ b/contests/ICPC_LA19/K.cpp
@@ -0,0 +1,63 @@
+/// K. Know your Aliens
+
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<ll,ll>;
+
+void mult(vector<ll> &ans, vector<ll> a, ii b) {
+  ans.resize(a.size() + 2);
+  fill(all(ans), 0);
+  for (int i = 0; i < a.size(); ++i) {
+    ans[i+0] += a[i] * b.fi;
+    ans[i+1] += a[i] * b.se;
+  }
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  string s; cin >> s;
+  vector<ii> v;
+  for (int i = 1; i < s.size(); ++i)
+    if (s[i] != s[i-1])
+      v.pb({1, -(2*i + 1)});
+
+  if (v.size() == 0) {
+    cout << 0 << ende;
+    return cout << ((s[0] == 'A') ? -1 : 1) << ende, 0;
+  }
+
+  vector<ll> ans = {v[0].fi, v[0].se};
+  for (int i = 1; i < v.size(); ++i)
+    mult(ans, ans, v[i]);
+
+  ll mul = 1LL;
+  if ((v.size() % 2 && s[0] == 'H') || (v.size() % 2 == 0 && s[0] == 'A'))
+    mul *= -1LL;
+
+  cout << v.size() << ende;
+  for (int i = 0; i <= v.size(); ++i) {
+    if (i) cout << " ";
+    cout << ans[i] * mul;
+  }
+  cout << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA19/L.cpp b/contests/ICPC_LA19/L.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ba4a2052774b4c129c2baf2a0b652aa8aada1cd
--- /dev/null
+++ b/contests/ICPC_LA19/L.cpp
@@ -0,0 +1,66 @@
+/// L. Leverage MDT
+
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int mat[1010][1010];
+int sum[1010][1010];
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, m; cin >> n >> m;
+  vector<string> v(n);
+  for (auto &i : v) cin >> i;
+
+  for (int i = 0; i < n; ++i)
+    for (int j = 1; j < m; ++j)
+      mat[i][j-1] = (v[i][j] == v[i][j-1]);
+
+  for (int i = 1; i < m; ++i)
+    sum[1][i] = mat[0][i-1];
+
+  for (int i = 2; i <= n; ++i)
+    for (int j = 1; j < m; ++j)
+      sum[i][j] = mat[i-1][j-1] + sum[i-1][j];
+
+  for (int i = 1; i <= n; ++i)
+    for (int j = 2; j < m; ++j)
+      sum[i][j] += sum[i][j-1];
+
+  auto query = [&](int i0, int j0, int i1, int j1) {
+    return sum[i1][j1] - sum[i0-1][j1] - sum[i1][j0-1] + sum[i0-1][j0-1];
+  };
+
+  int ans = 1;
+  for (int i = 1; i <= n; ++i)
+    for (int j = 1; j < m; ++j) {
+      int k = 1;
+      for (int b = min(n, m) + 1; b > 0; b /= 2)
+        while (i+k+b-1 <= n && i+k+b-2 <= m && query(i, j, i+b+k-1, j+b+k-2) == (k+b)*(k+b-1))
+          k += b;
+      ans = max(ans, k*k);
+    }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA19/M.cpp b/contests/ICPC_LA19/M.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5fb8446769bb4f6564a82ff86b565c653512624
--- /dev/null
+++ b/contests/ICPC_LA19/M.cpp
@@ -0,0 +1,45 @@
+/// M. Mountain Ranges
+
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, x; cin >> n >> x;
+  vector<int> v(n);
+  for (auto &i : v) cin >> i;
+
+  int ans = 0;
+  for (int i = 0; i < n; ++i) {
+    int cnt = 1;
+    for (int j = i+1; j < n; ++j)
+      if (v[j] - v[j-1] <= x)
+        cnt++;
+      else
+        break;
+    ans = max(ans, cnt);
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA19/a.out b/contests/ICPC_LA19/a.out
new file mode 100755
index 0000000000000000000000000000000000000000..b1262885b95493f626042d7f7dd7ce33aa7406a6
Binary files /dev/null and b/contests/ICPC_LA19/a.out differ
diff --git a/notebook/gen_latex.py b/notebook/gen_latex.py
index a8b4f3d6c04befb315d65ddc82d46904a2e67fb4..1474e8bafbc256fc504111ffce28e5056991ee99 100644
--- a/notebook/gen_latex.py
+++ b/notebook/gen_latex.py
@@ -141,24 +141,29 @@ class LatexGenerator:
                 write('\\begin{adjustwidth}{5pt}{5pt}\n')
 
             has_previous = False
+
+            # Description section
             if 'Description' in self.header:
                 write('\\textbf{\\footnotesize Description: }\n')
                 write('\\footnotesize{\\par %s}' % self.header['Description'])
                 write('\\\\\n')
                 has_previous = True
 
+            # Time complexity section
             if 'Time' in self.header:
                 if has_previous:
                     write('~\\\\\n')
                 output_complexity('Time')
                 has_previous = True
 
+            # Space complexity section
             if 'Space' in self.header:
                 if has_previous:
                     write('~\\\\\n')
                 output_complexity('Space')
                 has_previous = True
 
+            # Caution section
             if 'Caution' in self.header:
                 if has_previous:
                     write('\\\\\n')
@@ -228,6 +233,7 @@ class LatexGenerator:
         source.output_code(self._write)
         self._write('\\hrule\n')
 
+    # Adjust multicol param to use only 2 columns for problem solutions
     def _multicol(self, path):
         path = path.split('/')[0]
         num = {