diff --git a/algorithms/geometry/convex_hull.cpp b/algorithms/geometry/convex_hull.cpp
index 8929b85df0159ee60724a5a0ebac2d018f288f1f..b9fb75a6505b04888fc180e779db9947cca887a6 100644
--- a/algorithms/geometry/convex_hull.cpp
+++ b/algorithms/geometry/convex_hull.cpp
@@ -7,50 +7,51 @@
 
 typedef pair<double,double> dd;
 
-/**
- * The three points are a counter-clockwise turn if cross > 0, clockwise if
- * cross < 0, and collinear if cross = 0
- * @param a,b,c input points
- */
-double cross(dd a, dd b, dd c) {
-  return (b.fi - a.fi) * (c.se - a.se) - (b.se - a.se) * (c.fi - a.fi);
-}
-
-/**
- * Finds, among v, the points that form a convex hull
- * @param v vector of points
- */
-int convex_hull(const vector<dd> &v) {
-  int k = 0;
-  vector<int> ans(v.sz * 2);
-
-  // Sort points
-  sort(v.begin(), v.end(), [](const dd &a, const dd &b) -> bool {
-    return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
-  });
-
-  // Uppermost part of convex hull
-  for (int i = 0; i < v.sz; ++i) {
-    while (k >= 2 && cross(v[ans[k - 2]], v[ans[k - 1]], v[i]) < 0) 
-      k--;
-    ans[k++] = i;
+struct ConvexHull {
+  /**
+   * The three points are a counter-clockwise turn if cross > 0, clockwise if
+   * cross < 0, and collinear if cross = 0
+   * @param a,b,c input points
+   */
+  double cross(dd a, dd b, dd c) {
+    return (b.fi - a.fi) * (c.se - a.se) - (b.se - a.se) * (c.fi - a.fi);
   }
 
-  // Lowermost part of convex hull
-  for (int i = v.sz - 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;
+  /**
+   * Finds, among v, the points that form a convex hull
+   * @param v vector of points
+   */
+  int run(const vector<dd> &v) {
+    int k = 0;
+    vector<int> ans(v.sz * 2);
+
+    sort(v.begin(), v.end(), [](const dd &a, const dd &b) {
+      return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
+    });
+
+    // Uppermost part of convex hull
+    for (int i = 0; i < v.sz; ++i) {
+      while (k >= 2 && cross(v[ans[k - 2]], v[ans[k - 1]], v[i]) < 0) 
+        k--;
+      ans[k++] = i;
+    }
+
+    // Lowermost part of convex hull
+    for (int i = v.sz - 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;
+    }
+
+    // The ans vector contains the indices (relative to the sorted vector!) 
+    // of the points belonging to the convex hull
+    ans.resize(k);
+
+    // Remove duplicates
+    sort(all(ans));
+    ans.erase(unique(all(ans)), ans.end());
+
+    // Return number of points in the convex hull
+    return k - 1;
   }
-
-  // The ans vector contains the indices (relative to the sorted vector!) of 
-  // the points belonging to the convex hull
-  ans.resize(k);
-
-  // Remove duplicates
-  sort(all(ans));
-  ans.erase(unique(all(ans)), ans.end());
-
-  // Return number of points in the convex hull
-  return k - 1;
-}
+};
diff --git a/algorithms/graph/articulations_bridges.cpp b/algorithms/graph/articulations_bridges.cpp
index 5cab796f29ad6099f6593229869f6a09c1cdeef7..fdd4bae43b5d14dd2d6508ce8fbc883db935f337 100644
--- a/algorithms/graph/articulations_bridges.cpp
+++ b/algorithms/graph/articulations_bridges.cpp
@@ -6,77 +6,80 @@
  */
 
 vector<int> graph[MAX];
-int visited[MAX], parent[MAX];
 
-// The level of a node x (L[x]) is the "height" of x relative to the root
-// of the DFS
-int L[MAX];
+struct Tarjan {
+  int N;
+  vector<int> vis, par, L, low;
 
-// The low-link value of a node x (low[x]) is defined as the smallest level
-// of another node reachable from x when doing a DFS
-int low[MAX];
+  // Answer vector with bridges (edges)
+  vector<ii> brid;
 
-// Answer vector with bridges (edges)
-vector<ii> bridges;
+  // Answer vector with articulations (vertices)
+  vector<int> arti;
 
-// Answer vector with articulations (vertices)
-vector<int> articulations;
+  Tarjan(int N) :
+    N(N), vis(N), par(N), L(N), low(N)
+  {}
 
-/** 
- * Finds all articulations and bridges in the graph.
- * @param x root vertex
- */
-void dfs(int x) {
-  int child = 0;
-  visited[x] = 1;
-
-  for (auto i : graph[x]) {
-    if (!visited[i]) {
-      child++;
-      parent[i] = x;
-
-      // Initially low[i] is equal to low[x]
-      low[i] = L[i] = L[x] + 1;
-      dfs(i);
-
-      // After the DFS, low[i] might have changed, in that case, low[x]
-      // should be updated if a lower value has been found
-      low[x] = min(low[x], low[i]);
-
-      // If x is the root and has more than one child, or if it's not the
-      // root and the child i of x has no back edges, then x is an
-      // articulation vertex
-      if ((parent[x] == -1 && child > 1) || 
-          (parent[x] != -1 && low[i] >= L[x]))
-        articulations.pb(x);
-
-      // If node i can't reach a node above x (has no back edges), then it 
-      // the egde (x,i) is a bridge
-      if (low[i] > L[x])
-        bridges.pb(ii(x, i));
-
-    // If i has been visited but it's not x's parent, then i is "above" 
-    // (has smaller level then x), meaning that the edge (x,i) is a "back edge"
-    } else if (parent[x] != i)
-      low[x] = min(low[x], L[i]);
+  void init() {
+    fill(all(L), 0);
+    fill(all(vis), 0);
+    fill(all(par), -1);
   }
-}
 
-/**
- * Applies tarjan algorithm and format articulations vector.
- * @param x root vertex 
- */
-void tarjan(int n) {
-  mset(L, 0);
-  mset(visited, 0);
-  mset(parent, -1);
-
-  // Apply tarjan in every component
-  for (int i = 0; i < n; ++i)
-    if (!visited[i])
-      dfs(i);
-
-  // Remove duplicates for articulations
-  sort(all(articulations));
-  articulations.erase(unique(all(articulations)), articulations.end());
-}
+  /** 
+   * Finds all articulations and bridges in the graph.
+   * @param x root vertex
+   */
+  void dfs(int x) {
+    int child = 0;
+    vis[x] = 1;
+
+    for (auto i : graph[x]) {
+      if (!vis[i]) {
+        child++;
+        par[i] = x;
+
+        // Initially low[i] is equal to low[x]
+        low[i] = L[i] = L[x] + 1;
+        dfs(i);
+
+        // After the DFS, low[i] might have changed, in that case, low[x]
+        // should be updated if a lower value has been found
+        low[x] = min(low[x], low[i]);
+
+        // If x is the root and has more than one child, or if it's not the
+        // root and the child i of x has no back edges, then x is an
+        // articulation vertex
+        if ((par[x] == -1 && child > 1) || 
+            (par[x] != -1 && low[i] >= L[x]))
+          arti.pb(x);
+
+        // If node i can't reach a node above x (has no back edges), then it 
+        // the egde (x,i) is a bridge
+        if (low[i] > L[x])
+          brid.pb(ii(x, i));
+
+      // If i has been vis but it's not x's par, then i is "above" 
+      // (has smaller level then x), meaning that the edge (x,i) 
+      // is a "back edge"
+      } else if (par[x] != i)
+        low[x] = min(low[x], L[i]);
+    }
+  }
+
+  /**
+   * Applies tarjan algorithm and format articulations vector.
+   */
+  void run() {
+
+    // Apply tarjan in every component
+    for (int i = 0; i < N; ++i)
+      if (!vis[i])
+        dfs(i);
+
+    // Remove duplicates for articulations
+    sort(all(arti));
+    arti.erase(unique(all(arti)), arti.end());
+  }
+};
diff --git a/algorithms/graph/bellman_ford.cpp b/algorithms/graph/bellman_ford.cpp
index f512b2ced604124612bfe96b7aa05cb5f86277b3..9554f9201c1e9e32480db979829fb1dbacbfc856 100644
--- a/algorithms/graph/bellman_ford.cpp
+++ b/algorithms/graph/bellman_ford.cpp
@@ -5,32 +5,48 @@
  * Complexity (Space): O(V + E)
  */
 
-struct edge { int u, v, w; };
+struct Edge { 
+  int u, v, w; 
 
-int dist[MAX];
-vector<edge> graph;
+  Edge(int u, int v, int w) :
+    u(u), v(v), w(w)
+  {}
+};
 
-/**
- * Returns distance between s and d in a graph with V vertices
- * using bellman_ford.
- * @param s,d origin and destination vertices
- * @param V number of vertices
- */
-int bellman_ford(int s, int d, int V) {
-  mset(dist, inf);
-  dist[s] = 0;
+vector<Edge> graph;
 
-  // Iterate through all edges V times computing the shortest distance
-  // to all vertices from s
-  for (int i = 0; i < V; ++i)
-    for (auto e : graph)
-      if (dist[e.u] != inf && dist[e.u] + e.w < dist[e.v])
-        dist[e.v] = dist[e.u] + e.w;
+struct BellmanFord {
+  int N;
+  vector<int> dist;
+
+  BellmanFord(int N) : 
+    N(N), dist(N)
+  {}
 
-  // Check for negative cycles, return -inf if there is one
-  for (auto e : graph)
-    if (dist[e.u] != inf && dist[e.u] + w < dist[e.v])
-      return -inf;
+  void init() {
+    fill(all(dist), inf);
+  }
+
+  /**
+   * Returns distance between s and d in a graph with N vertices
+   * using bellman_ford.
+   * @param s,d origin and destination vertices
+   */
+  int run(int s, int d) {
+    dist[s] = 0;
+
+    // Iterate through all edges N times computing the shortest distance
+    // to all vertices from s
+    for (int i = 0; i < N; ++i)
+      for (auto e : graph)
+        if (dist[e.u] != inf && dist[e.u] + e.w < dist[e.v])
+          dist[e.v] = dist[e.u] + e.w;
+
+    // Check for negative cycles, return -inf if there is one
+    for (auto e : graph)
+      if (dist[e.u] != inf && dist[e.u] + w < dist[e.v])
+        return -inf;
 
-  return dist[d];
-}
+    return dist[d];
+  }
+};
diff --git a/algorithms/graph/bfs.cpp b/algorithms/graph/bfs.cpp
index e7bfa631c6d8a70485a80588b9af838cbdff71c6..e57b55dce84e6f3c7e2996095b41864ea73691e5 100644
--- a/algorithms/graph/bfs.cpp
+++ b/algorithms/graph/bfs.cpp
@@ -5,26 +5,37 @@
  * Complexity (Space): O(V + E)
  */
 
-bool cont[MAX];
 vector<int> graph[MAX];
 
-/**
- * Applies BFS on graph.
- * @param x starting vertex
- */
-void bfs(int x) {
-  queue<int> Q;
+struct BFS {
+  int N;
+  vector<int> vis;
+
+  BFS(int N) :
+    N(N), vis(N)
+  {}
+
+  void init() {
+    fill(all(vis), 0);
+  }
+
+  /**
+   * Applies BFS on graph.
+   * @param x starting vertex
+   */
+  void run(int x) {
+    queue<int> Q;
 
-  Q.push(x);
-  cont[x] = true;
+    Q.push(x);
+    vis[x] = true;
 
-  while (!Q.empty()) {
-    int v = Q.front();
-    Q.pop();
-    cont[v] = true;
+    while (!Q.empty()) {
+      int v = Q.front(); Q.pop();
+      vis[v] = true;
 
-    for (auto i : graph[v])
-      if (!cont[i])
-        Q.push(i);
+      for (auto i : graph[v])
+        if (!vis[i])
+          Q.push(i);
+    }
   }
-}
+};
diff --git a/algorithms/graph/bipartite_match.cpp b/algorithms/graph/bipartite_match.cpp
index b04c34746354e3bd5335b7357e06732e786579f9..f5bb7f084926d7a9b091664c9ea1d688b464ec24 100644
--- a/algorithms/graph/bipartite_match.cpp
+++ b/algorithms/graph/bipartite_match.cpp
@@ -6,39 +6,49 @@
  */
 
 vector<int> graph[MAX];
-int cont[MAX], match[MAX];
 
-/**
- * Finds match for x.
- * @param x starting vertex
- */
-int dfs(int x) {
-  if (cont[x])
-    return 0;
+struct BipartiteMatching {
+  int N;
+  vector<int> vis, match;
 
-  cont[x] = 1;
-  for (auto i : graph[x])
-    if (match[i] == -1 || dfs(match[i])) {
-      match[i] = x;
-      return 1;
-    }
+  BipartiteMatching(int N) :
+    N(N), vis(N), match(N)
+  {}
 
-  return 0;
-}
+  void init() {
+    fill(all(vis), 0);
+    fill(all(match), -1);
+  }
 
-/**
- * Returns number of left elements in matching and fills match array with the 
- * match itself (match[right_i] = left_i).
- * @param n number of vertices on the left
- */
-int bipartite_matching(int n) {
-  int ans = 0;
-  mset(match, -1);
+  /**
+   * Finds match for x.
+   * @param x starting vertex
+   */
+  int dfs(int x) {
+    if (vis[x])
+      return 0;
 
-  for (int i = 0; i < n; ++i) {
-    mset(cont, 0);
-    ans += dfs(i);
+    vis[x] = 1;
+    for (auto i : graph[x])
+      if (match[i] == -1 || dfs(match[i])) {
+        match[i] = x;
+        return 1;
+      }
+
+    return 0;
   }
 
-  return ans;
-}
+  /**
+   * Returns number of left elements in matching and fills match array with 
+   * the match itself (match[right_i] = left_i).
+   * @param n number of vertices on the left
+   */
+  int run() {
+    int ans = 0;
+
+    for (int i = 0; i < N; ++i)
+      ans += dfs(i);
+
+    return ans;
+  }
+};
diff --git a/algorithms/graph/dfs.cpp b/algorithms/graph/dfs.cpp
index 1e6b06754fa96be11ea55cde1d88e2b8b6a31910..c0d9dc576987131f4cacc8c2ebb8670900205c51 100644
--- a/algorithms/graph/dfs.cpp
+++ b/algorithms/graph/dfs.cpp
@@ -5,16 +5,28 @@
  * Complexity (Space): O(V + E)
  */
 
-bool cont[MAX];
 vector<int> graph[MAX];
 
-/**
- * Applies DFS on graph.
- * @param x starting vertex
- */
-void dfs(int x) {
-  cont[x] = true;
-  for (auto i : graph[x])
-    if (!cont[i])
-      dfs(x);
+struct DFS {
+  int N;
+  vector<bool> vis;
+
+  DFS(int N) :
+    N(N), vis(N)
+  {}
+
+  void init() {
+    fill(all(vis), 0);
+  }
+
+  /**
+   * Applies DFS on graph.
+   * @param x starting vertex
+   */
+  void run(int x) {
+    vis[x] = true;
+    for (auto i : graph[x])
+      if (!vis[i])
+        run(x);
+  }
 }
diff --git a/algorithms/graph/dijkstra.cpp b/algorithms/graph/dijkstra.cpp
index 510c31c1d9ac1e365ac9534d1931ab225ebd7a26..01f639d95958ed845749b338b0557e19f464332d 100644
--- a/algorithms/graph/dijkstra.cpp
+++ b/algorithms/graph/dijkstra.cpp
@@ -5,43 +5,50 @@
  * Complexity (Space): O(V + E)
  */
 
-int dist[MAX];
-vector<ii> graph[MAX];
+vector<int> graph[MAX];
 
-/**
- * Returns shortest distance from s to d
- * @param s,d origin and destination vertices
- */
-int dijkstra(int s, int d) {
-  set<ii> pq;
-  int u, v, wt;
+struct Dijkstra {
+  int N;
+  vector<int> dist, vis;
+
+  Dijkstra(int N) :
+    N(N), dist(N), vis(N)
+  {}
 
-  mset(dist, inf);
+  void init() {
+    fill(all(vis), 0);
+    fill(all(dist), inf);
+  }
 
-  dist[s] = 0;
-  pq.insert(ii(0, s));
+  /**
+   * Returns shortest distance from s to d
+   * @param s,d origin and destination vertices
+   */
+  int run(int s, int d) {
+    set<ii> pq;
 
-  while (pq.size() != 0) {
-    u = pq.begin()->second;
-    pq.erase(pq.begin());
+    dist[s] = 0;
+    pq.insert(ii(0, s));
 
-    for (auto i : graph[u]) {
-      v = i.first;
-      wt = i.second;
+    while (pq.size() != 0) {
+      int u = pq.begin()->se;
+      pq.erase(pq.begin());
 
-      // If the distance to v can be improved from d, improve it
-      if (dist[v] > dist[u] + wt) {
+      if (vis[u]) continue;
+      vis[u] = 1;
 
-        // Erase v from pq, because the distance was updated, if 
-        // the distance is inf, then v is not on pq
-        if (dist[v] != inf)
-          pq.erase(pq.find(ii(dist[v], v)));
+      for (auto i : graph[u]) {
+        int v = i.fi;
+        int wt = i.se;
 
-        dist[v] = dist[u] + wt;
-        pq.insert(ii(dist[v], v));
+        // If the distance to v can be improved from d, improve it
+        if (!vis[v] && dist[v] > dist[u] + wt) {
+          dist[v] = dist[u] + wt;
+          pq.insert(ii(dist[v], v));
+        }
       }
     }
-  }
 
-  return dist[d];
-}
+    return dist[d];
+  }
+};
diff --git a/algorithms/graph/dinic.cpp b/algorithms/graph/dinic.cpp
index 38d6078f5bb8841eb2f9c1687f440360a4289c26..caf4862fc087f5fc0228b723285a331270b8f7ee 100644
--- a/algorithms/graph/dinic.cpp
+++ b/algorithms/graph/dinic.cpp
@@ -5,108 +5,102 @@
  * Complexity (Space): O(V + E)
  */
 
-// Edge struct to be used in adjacency list similar to vector<ii> graph[MAX], 
-// but storing more information than ii.
-struct edge {
-  int u;
-  int flow, cap;
+struct Dinic {
+  struct Edge {
+    int u, flow, cap, rev;
 
-  // Id of the reverse edge on graph[u]
-  int rev;
+    Edge(int u, int flow, int cap, int rev) :
+      u(u), flow(flow), cap(cap), rev(rev) 
+    {}
+  };
 
-  edge(int u, int flow, int cap, int rev) :
-    u(u), flow(flow), cap(cap), rev(rev)
-  {}
-};
-
-int depth[MAX];
-int start[MAX];
-vector<edge> graph[MAX];
+  int N;
+  vector<int> depth, start;
+  vector<vector<Edge>> graph;
 
-/**
- * Adds edge to the graph.
- * @param s,t origin and destination of edge
- * @param c capacity of edge
- */
-void add_edge(int s, int t, int c) {
-  edge forward(t, 0, c, graph[t].size());
-  edge backward(s, 0, 0, graph[s].size());
+  Dinic(int N) : 
+    N(N), depth(N), start(N), graph(N) 
+  {}
 
-  graph[s].pb(forward);
-  graph[t].pb(backward);
-}
+  /**
+   * Adds edge to the graph.
+   * @param s,t origin and destination of edge
+   * @param c capacity of edge
+   */
+  void add_edge(int s, int t, int c) {
+    Edge forward(t, 0, c, graph[t].size());
+    Edge backward(s, 0, 0, graph[s].size());
+
+    graph[s].pb(forward);
+    graph[t].pb(backward);
+  }
 
-/**
- * Calculates depth of each vertex from source, considering only
- * edges with remaining capacity.
- * @param s,t source and sink of flow graph
- */
-bool bfs(int s, int t) {
-  queue<int> Q;
-  Q.push(s);
-
-  mset(depth, -1);
-  depth[s] = 0;
-
-  while (!Q.empty()) {
-    int v = Q.front(); Q.pop();
-    
-    for (auto i : graph[v]) {
-      if (depth[i.u] == -1 && i.flow < i.cap) {
-        depth[i.u] = depth[v] + 1;
-        Q.push(i.u);
+  /**
+   * Calculates depth of each vertex from source, considering only
+   * edges with remaining capacity.
+   * @param s,t source and sink of flow graph
+   */
+  bool bfs(int s, int t) {
+    queue<int> Q;
+    Q.push(s);
+
+    mset(depth, -1);
+    depth[s] = 0;
+
+    while (!Q.empty()) {
+      int v = Q.front(); Q.pop();
+
+      for (auto i : graph[v]) {
+        if (depth[i.u] == -1 && i.flow < i.cap) {
+          depth[i.u] = depth[v] + 1;
+          Q.push(i.u);
+        }
       }
     }
-  }
 
-  return depth[t] != -1;
-}
+    return depth[t] != -1;
+  }
 
-/**
- * Finds bottleneck flow and add to the edges belonging to the paths found.
- * @param s,t source and sink of flow graph
- * @param flow minimum flow so far
- */
-int dfs(int s, int t, int flow) {
-  if (s == t)
-    return flow;
-
-  // Start iteration from where it last stopped to avoid repetitions
-  for ( ; start[s] < graph[s].size(); ++start[s]) {
-    edge &e = graph[s][start[s]];
-
-    // If the next vertex is further from the source (and closer to the sink)
-    // and the edge is not at full capacity, then explore it
-    if (depth[e.u] == depth[s] + 1 && e.flow < e.cap) {
-      int min_flow = dfs(e.u, t, min(flow, e.cap - e.flow));
-
-      if (min_flow > 0) {
-        e.flow += min_flow;
-        graph[e.u][e.rev].flow -= min_flow;
-        return min_flow;
+  /**
+   * Finds bottleneck flow and add to the edges belonging to the paths found.
+   * @param s,t source and sink of flow graph
+   * @param flow minimum flow so far
+   */
+  int dfs(int s, int t, int flow) {
+    if (s == t)
+      return flow;
+
+    for ( ; start[s] < graph[s].size(); ++start[s]) {
+      Edge &e = graph[s][start[s]];
+
+      if (depth[e.u] == depth[s] + 1 && e.flow < e.cap) {
+        int min_flow = dfs(e.u, t, min(flow, e.cap - e.flow));
+
+        if (min_flow > 0) {
+          e.flow += min_flow;
+          graph[e.u][e.rev].flow -= min_flow;
+          return min_flow;
+        }
       }
     }
+
+    return 0;
   }
 
-  return 0;
-}
+  /**
+   * Returns maximum flow.
+   * @param s,t source and sink of flow graph
+   */
+  int run(int s, int t) {
+    int ans = 0;
 
-/**
- * Returns maximum flow.
- * @param s,t source and sink of flow graph
- */
-int dinic(int s, int t) {
-  int ans = 0;
+    while (bfs(s, t)) {
+      fill(all(start), 0);
 
-  // Run bfs to set depth array (depth of each vertex from source)
-  while (bfs(s, t)) {
-    mset(start, 0);
+      while (int flow = dfs(s, t, inf))
+        ans += flow;
+    }
 
-    // Find every available path from the current depth information,
-    // set the flow of the edges and add the pushed flow to the answer
-    while (int flow = dfs(s, t, inf))
-      ans += flow;
+    return ans;
   }
-
-  return ans;
-}
+};
diff --git a/algorithms/graph/edmonds_karp.cpp b/algorithms/graph/edmonds_karp.cpp
index 5e3243fb9d4dd5dd12f677481c667bbebb4dcfbf..e9bdb31cdff335a67374b0bbe0678230ff69c44f 100644
--- a/algorithms/graph/edmonds_karp.cpp
+++ b/algorithms/graph/edmonds_karp.cpp
@@ -5,68 +5,77 @@
  * Complexity (space): O(V^2)
  */
 
-int N;
-int par[MAX];
-int graph[MAX][MAX], rg[MAX][MAX];
+int rg[MAX][MAX];
+int graph[MAX][MAX];
 
-bool cont[MAX];
+struct EdmondsKarp {
+  int N;
+  vector<int> par, vis;
 
-/**
- * Finds if there's a path between s and t using non-full
- * residual edges.
- * @param s,t source and sink of flow graph
- */
-bool bfs(int s, int t) {
-  queue<int> Q;
-  Q.push(s);
-  cont[s] = true;
-
-  while (!Q.empty()) {
-    int u = Q.front(); Q.pop();
-
-    // Sink was found, there is a path
-    if (u == t)
-      return true;
-
-    for (int i = 0; i < N; ++i)
-      if (!cont[i] && rg[u][i]) {
-        cont[i] = true;
-        par[i] = u;
-        Q.push(i);
-      }
+  EdmondsKarp(int N) :
+    N(N), par(N), vis(N), 
+  {}
+
+  void init() {
+    fill(all(vis), 0);
   }
 
-  return false;
-}
+  /**
+   * Finds if there's a path between s and t using non-full
+   * residual edges.
+   * @param s,t source and sink of flow graph
+   */
+  bool bfs(int s, int t) {
+    queue<int> Q;
+    Q.push(s);
+    vis[s] = true;
 
-/**
- * Returns maximum flow.
- * @param s,t source and sink of flow graph
- */
-int edmonds_karp(int s, int t) {
-  int ans = 0;
-  par[s] = -1;
+    while (!Q.empty()) {
+      int u = Q.front(); Q.pop();
 
-  mset(cont, 0);
-  memcpy(rg, graph, sizeof(graph));
+      // Sink was found, there is a path
+      if (u == t)
+        return true;
 
-  // Repeat while there's a valid path between s and t
-  while (bfs(s, t)) {
-    int flow = inf;
+      for (int i = 0; i < N; ++i)
+        if (!vis[i] && rg[u][i]) {
+          vis[i] = true;
+          par[i] = u;
+          Q.push(i);
+        }
+    }
 
-    // Get the minimum capacity among all edges of the chosen path
-    for (int i = t; par[i] != -1; i = par[i])
-      flow = min(flow, rg[par[i]][i]);
+    return false;
+  }
 
-    // Update residual graph
-    for (int i = t; par[i] != -1; i = par[i]) {
-      rg[par[i]][i] -= flow;
-      rg[i][par[i]] += flow;
+  /**
+   * Returns maximum flow.
+   * @param s,t source and sink of flow graph
+   */
+  int run(int s, int t) {
+    int ans = 0;
+    par[s] = -1;
+
+    memcpy(rg, graph, sizeof(graph));
+
+    // Repeat while there's a valid path between s and t
+    while (bfs(s, t)) {
+      int flow = inf;
+
+      // Get the minimum capacity among all edges of the chosen path
+      for (int i = t; par[i] != -1; i = par[i])
+        flow = min(flow, rg[par[i]][i]);
+
+      // Update residual graph
+      for (int i = t; par[i] != -1; i = par[i]) {
+        rg[par[i]][i] -= flow;
+        rg[i][par[i]] += flow;
+      }
+
+      ans += flow;
+      init();
     }
 
-    ans += flow;
-    mset(cont, 0);
+    return ans;
   }
-
-  return ans;
-}
+};
diff --git a/algorithms/graph/floyd_warshall.cpp b/algorithms/graph/floyd_warshall.cpp
index 5fbe5916b60d8da7bab5e9e53a7b248138749d57..d93b55655891a74288f24375a4ea15884584c5b4 100644
--- a/algorithms/graph/floyd_warshall.cpp
+++ b/algorithms/graph/floyd_warshall.cpp
@@ -8,17 +8,24 @@
 int dist[MAX][MAX];
 int graph[MAX][MAX];
 
-/**
- * Computes shortest path between all pairs of vertices.
- * @param n number of vertices
- */
-int floyd_warshall(int n) {
-  for (int i = 0; i < n; ++i)
-    for (int j = 0; j < n; ++j)
-      dist[i][j] = graph[i][j];
+struct FloydWarshall {
+  int N;
+  
+  FloydWarshall(int N) :
+    N(N)
+  {}
+
+  /**
+   * Computes shortest path between all pairs of vertices.
+   */
+  int run() {
+    for (int i = 0; i < N; ++i)
+      for (int j = 0; j < N; ++j)
+        dist[i][j] = graph[i][j];
 
-  for (int k = 0; k < n; ++k)
-    for (int i = 0; i < n; ++i)
-      for (int j = 0; j < n; ++j)
-        dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
-}
+    for (int k = 0; k < N; ++k)
+      for (int i = 0; i < N; ++i)
+        for (int j = 0; j < N; ++j)
+          dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
+  }
+};
diff --git a/algorithms/graph/ford_fulkerson.cpp b/algorithms/graph/ford_fulkerson.cpp
index 3930726d56f9ae7f744fcb4353b6cb73f95c40a5..6ffcae0a0f3bca1ce69c4c019ff0f9b574b67e2d 100644
--- a/algorithms/graph/ford_fulkerson.cpp
+++ b/algorithms/graph/ford_fulkerson.cpp
@@ -5,61 +5,70 @@
  * Complexity (space): O(V^2)
  */
 
-int N;
-int par[MAX];
-int graph[MAX][MAX], rg[MAX][MAX];
+int rg[MAX][MAX];
+int graph[MAX][MAX];
 
-bool cont[MAX];
+struct FordFulkerson {
+  int N;
+  vector<int> par, vis;
 
-/**
- * Finds if there's a path between s and t using non-full
- * residual edges.
- * @param s,t source and sink of flow graph
- */
-bool dfs(int s, int t) {
-  cont[s] = true;
-  if (s == t)
-    return true;
+  FordFulkerson(int N) :
+    N(N), par(N), vis(N)
+  {}
 
-  for (int i = 0; i < N; ++i)
-    if (!cont[i] && rg[s][i]) {
-      par[i] = s;
+  void init() {
+    fill(all(vis), 0);
+  }
 
-      if (dfs(i, t)) 
-        return true;
-    }
+  /**
+   * Finds if there's a path between s and t using non-full
+   * residual edges.
+   * @param s,t source and sink of flow graph
+   */
+  bool dfs(int s, int t) {
+    vis[s] = true;
+    if (s == t)
+      return true;
 
-  return false;
-}
+    for (int i = 0; i < N; ++i)
+      if (!vis[i] && rg[s][i]) {
+        par[i] = s;
 
-/**
- * Returns maximum flow.
- * @param s,t source and sink of flow graph
- */
-int ford_fulkerson(int s, int t) {
-  int ans = 0;
-  par[s] = -1;
+        if (dfs(i, t)) 
+          return true;
+      }
 
-  mset(cont, 0);
-  memcpy(rg, graph, sizeof(graph));
+    return false;
+  }
+
+  /**
+   * Returns maximum flow.
+   * @param s,t source and sink of flow graph
+   */
+  int run(int s, int t) {
+    int ans = 0;
+    par[s] = -1;
+
+    memcpy(rg, graph, sizeof(graph));
 
-  // Repeat while there's a valid path between s and t
-  while (dfs(s, t)) {
-    int flow = inf;
+    // Repeat while there's a valid path between s and t
+    while (dfs(s, t)) {
+      int flow = inf;
 
-    // Get the minimum capacity among all edges of the chosen path
-    for (int i = t; par[i] != -1; i = par[i])
-      flow = min(flow, rg[par[i]][i]);
+      // Get the minimum capacity among all edges of the chosen path
+      for (int i = t; par[i] != -1; i = par[i])
+        flow = min(flow, rg[par[i]][i]);
 
-    // Update residual graph
-    for (int i = t; par[i] != -1; i = par[i]) {
-      rg[par[i]][i] -= flow;
-      rg[i][par[i]] += flow;
+      // Update residual graph
+      for (int i = t; par[i] != -1; i = par[i]) {
+        rg[par[i]][i] -= flow;
+        rg[i][par[i]] += flow;
+      }
+
+      ans += flow;
+      init();
     }
 
-    ans += flow;
-    mset(cont, 0);
+    return ans;
   }
-
-  return ans;
-}
+};
diff --git a/algorithms/graph/hopcroft_karp.cpp b/algorithms/graph/hopcroft_karp.cpp
index d82719154d255b1f089ed88a4795d058bf4ac8e0..2ba0ffef1e25b8057d17fbc1ebbbf1184bc83642 100644
--- a/algorithms/graph/hopcroft_karp.cpp
+++ b/algorithms/graph/hopcroft_karp.cpp
@@ -5,86 +5,93 @@
  * Complexity (Space): O(V + E)
  */
 
-int dist[MAX];
-int matchL[MAX], matchR[MAX];
-
 vector<int> graph[MAX];
 
-/**
- * Builds an alternating level graph rooted at unmatched vertices in L
- * using BFS, and returns whether there is an augmenting path in the graph
- * or not.
- * @param n number of vertices on the left
- */
-bool bfs(int n) {
-  queue<int> Q;
-
-  // Add unmatched vertices in L to the queue
-  for (int l = 1; l <= n; ++l)
-    if (matchL[l] == 0) {
-      dist[l] = 0;
-      Q.push(l);
-    } else
-      dist[l] = inf;
+struct HopcroftKarp {
+  int L, R;
+  vector<int> dist;
+  vector<int> matchL, matchR;
 
-  dist[0] = inf;
-  while (!Q.empty()) {
-    int l = Q.front(); Q.pop();
+  HopcroftKarp(int L, int R) :
+    L(L), R(R), dist(L),
+    matchL(L), matchR(R)
+  {}
 
-    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]);
-        }
-    }
+  void init() {
+    fill(all(matchL), 0);
+    fill(all(matchR), 0);
   }
 
-  return (dist[0] != inf);
-}
+  /**
+   * Builds an alternating level graph rooted at unmatched vertices in L
+   * using BFS, and returns whether there is an augmenting path in the graph
+   * or not.
+   */
+  bool bfs() {
+    queue<int> Q;
 
-/**
- * Augments path starting in l if there is one, returns
- * whether a path was augmented or not.
- * @param l initial free vertex on the left
- */
-bool dfs(int l) {
-  if (l == 0)
-    return true;
-  
-  for (auto r : graph[l]) {
+    // Add unmatched vertices in L to the queue
+    for (int l = 1; l <= L; ++l) {
+      if (matchL[l] == 0) {
+        dist[l] = 0;
+        Q.push(l);
+      } else {
+        dist[l] = inf;
+      }
+    }
+
+    dist[0] = inf;
+    while (!Q.empty()) {
+      int l = Q.front(); Q.pop();
 
-    // The augmenting path has increasing dist, set by the BFS
-    if (dist[matchR[r]] == dist[l] + 1)
-      if (dfs(matchR[r])) {
-        matchR[r] = l;
-        matchL[l] = r;
-        return true;
+      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]);
+          }
+        }
       }
+    }
+
+    return (dist[0] != inf);
   }
 
-  dist[l] = inf;
-  return false;
-}
+  /**
+   * Augments path starting in l if there is one, returns
+   * whether a path was augmented or not.
+   * @param l initial free vertex on the left
+   */
+  bool dfs(int l) {
+    if (l == 0)
+      return true;
 
-/**
- * Returns number of matched vertices on the left (matched edges).
- * @param n number of vertices on the left
- */
-int hopcroft_karp(int n) {
-  mset(matchL, 0);  
-  mset(matchR, 0);  
+    for (auto r : graph[l]) {
+      if (dist[matchR[r]] == dist[l] + 1) {
+        if (dfs(matchR[r])) {
+          matchR[r] = l;
+          matchL[l] = r;
+          return true;
+        }
+      }
+    }
 
-  int ans = 0;
+    dist[l] = inf;
+    return false;
+  }
 
-  // While there is an augmenting path
-  while (bfs(n)) {
+  /**
+   * Returns number of matched vertices on the left (matched edges).
+   */
+  int run() {
+    int ans = 0;
 
-    // Augment the path when is possible
-    for (int l = 1; l <= n; ++l)
-      if (matchL[l] == 0 && dfs(l))
-        ans++;
-  }
+    while (bfs(L)) {
+      for (int l = 1; l <= L; ++l)
+        if (matchL[l] == 0 && dfs(l))
+          ans++;
+    }
 
-  return ans;
-}
+    return ans;
+  }
+};
diff --git a/algorithms/graph/kosaraju.cpp b/algorithms/graph/kosaraju.cpp
index 3a789e9df7e056cd882b0d969eaa75259a3fbd28..72af95464743277aa85cba37cae76e8335eb1e89 100644
--- a/algorithms/graph/kosaraju.cpp
+++ b/algorithms/graph/kosaraju.cpp
@@ -5,67 +5,77 @@
  * Complexity (Space): O(V + E)
  */
 
-stack<int> S;
 vector<int> graph[MAX];
 vector<int> transp[MAX];
 
-bool cont[MAX];
+struct Kosaraju {
+  int N;
+  stack<int> S;
+  vector<int> vis;
 
-/**
- * Traverses a SCC.
- * @param x initial vertex
- */
-void dfs(int x) {
-  // x belong to current scc
-  cont[x] = true;
+  Kosaraju(int N) :
+    N(N), vis(N)
+  {}
 
-  for (auto i : transp[x])
-    if (!cont[i])
-      dfs(i);
-}
+  void init() {
+    fill(all(vis), 0);
+  }
 
-/**
- * Fills stack with DFS starting points to find SCC.
- * @param x initial vertex
- */
-void fill_stack(int x) {
-  cont[x] = true;
+  /**
+   * Traverses a SCC.
+   * @param x initial vertex
+   */
+  void dfs(int x) {
+    vis[x] = true;
 
-  for (auto i : graph[x])
-    if (!cont[i])
-      fill_stack(i);
+    for (auto i : transp[x])
+      if (!vis[i])
+        dfs(i);
+  }
 
-  S.push(x);
-}
+  /**
+   * Fills stack with DFS starting points to find SCC.
+   * @param x initial vertex
+   */
+  void fill_stack(int x) {
+    vis[x] = true;
 
-/**
- * Returns number of SCC of a graph.
- * @param n number of vertices
- */
-int kosaraju(int n) {
-  int scc = 0;
-
-  mset(cont, 0);
-  for (int i = 0; i < n; ++i)
-    if (!cont[i])
-      fill_stack(i);
-
-  // Transpose graph
-  for (int i = 0; i < n; ++i)
-    for (auto j : graph[i])
-      transp[j].push_back(i);
-
-  // Count SCC
-  mset(cont, 0);
-  while (!S.empty()) {
-    int v = S.top();
-    S.pop();
-
-    if (!cont[v]) {
-      dfs(v);
-      scc++;
-    }
+    for (auto i : graph[x])
+      if (!vis[i])
+        fill_stack(i);
+
+    S.push(x);
   }
 
-  return scc;
-}
+  /**
+   * Returns number of SCC of a graph.
+   */
+  int run() {
+    int scc = 0;
+
+    init();
+    for (int i = 0; i < N; ++i)
+      if (!vis[i])
+        fill_stack(i);
+
+    // Transpose graph
+    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/kruskal.cpp b/algorithms/graph/kruskal.cpp
index bda5b7eb13268524afa5d7ce465dc35395650de1..26b8c941eaa66b71c7647412ca9310e90a82a97a 100644
--- a/algorithms/graph/kruskal.cpp
+++ b/algorithms/graph/kruskal.cpp
@@ -5,40 +5,47 @@
  * Complexity (Space): O(E)
  * 
  * #include <structure/disjoint_set>
- *
- * OBS: * = return maximum spanning tree
  */
 
 typedef pair<ii,int> iii;
 vector<iii> edges;
 
-/**
- * Returns value of MST.
- * @param mst[out] vector with edges of computed MST
- */
-int kruskal(vector<iii> &mst) {
-
-  // Sort by weight of the edges
-  sort(all(edges), [&](const iii &a, const iii &b) {
-    return a.se < b.se;
-    //* return a.se > b.se
-  });
-
-  int size = 0;
-  for (int i = 0; i < MAX; i++)
-    make_set(i);
-
-  for (int i = 0; i < edges.size(); i++) {
-    int pu = find_set(edges[i].fi.fi);
-    int pv = find_set(edges[i].fi.se);
-
-    // If the sets are different, then the edge i does not close a cycle
-    if (pu != pv) {
-      mst.pb(edges[i]);
-      size += edges[i].se;
-      union_set(pu, pv);
+struct Kruskal {
+  int N;
+  DisjointSet ds;
+
+  Kruskal(int N) :
+    N(N), ds(N)
+  {}
+
+  /**
+   * Returns value of MST.
+   * @param mst[out] vector with edges of computed MST
+   */
+  int run(vector<iii> &mst) {
+
+    // Sort by weight of the edges
+    sort(all(edges), [&](const iii &a, const iii &b) {
+      return a.se < b.se; // ('>' for maximum spanning tree)
+    });
+
+
+    int size = 0;
+    for (int i = 0; i < N; i++)
+      ds.make_set(i);
+
+    for (int i = 0; i < edges.size(); i++) {
+      int pu = ds.find_set(edges[i].fi.fi);
+      int pv = ds.find_set(edges[i].fi.se);
+
+      // If the sets are different, then the edge i does not close a cycle
+      if (pu != pv) {
+        mst.pb(edges[i]);
+        size += edges[i].se;
+        ds.union_set(pu, pv);
+      }
     }
-  }
 
-  return size;
-}
+    return size;
+  }
+};
diff --git a/algorithms/graph/lca.cpp b/algorithms/graph/lca.cpp
index 0d638e94f6e019b8a96d0d6ab5d58f545c4910ae..b3faae5429289293dbdbf10a7ef51a7190125917 100644
--- a/algorithms/graph/lca.cpp
+++ b/algorithms/graph/lca.cpp
@@ -13,78 +13,81 @@
 
 #define MAXLOG 20 //log2(MAX)
 
-vector<int> graph[MAX]; //*** vector<ii>
-
 int h[MAX];
 int par[MAX][MAXLOG];
 //*** int cost[MAX][MAXLOG];
 
-/**
- * Performs DFS while filling h, par, and cost.
- * @param v root of the tree
- */
-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;
-
-  for (int i = 1; i < MAXLOG; ++i)
-    if (par[v][i - 1] != -1) {
-      par[v][i] = par[par[v][i - 1]][i - 1];
-      //* cost[v][i] += cost[v][i - 1] + cost[par[v][i - 1]][i - 1];
-      //** cost[v][i] = max(cost[v][i], max(cost[par[v][i-1]][i-1], cost[v][i-1]));
-    }
-
-  for (auto u : graph[v]) 
-    if (p != u.fi)
-      dfs(u.fi, v, u.se);
-}
-
-/**
- * Preprocess tree.
- * @param v root of the tree
- */
-void preprocess(int v) {
-  mset(par, -1);
-  //*** mset(cost, 0;
-  dfs(v);
-}
+vector<int> graph[MAX]; //*** vector<ii>
 
-/**
- * Returns LCA (or sum or max).
- * @param p,q query nodes 
- */
-int query(int p, int q) {
-  //*** int ans = 0;
-
-  if (h[p] < h[q])
-    swap(p, q);
-
-  for (int i = MAXLOG - 1; i >= 0; --i)
-    if (par[p][i] != -1 && h[par[p][i]] >= h[q]) {
-      //* ans += cost[p][i];
-      //** ans = max(ans, cost[p][i]);
-      p = par[p][i];
-    }
-
-  if (p == q)
-    return p; //*** return ans;
-
-  for (int i = MAXLOG - 1; i >= 0; --i)
-    if (par[p][i] != -1 && par[p][i] != par[q][i]) {
-      //* ans += cost[p][i] + cost[q][i];
-      //** ans = max(ans, max(cost[p][i], cost[q][i]));
-      p = par[p][i];
-      q = par[q][i];
-    }
-
-  //* if (p == q) return ans;
-  //* else return ans + cost[p][0] + cost[q][0];
-
-  //** if (p == q) return ans;
-  //** else return max(ans, max(cost[p][0], cost[q][0]));
-
-  return par[p][0];
-}
+struct LCA {
+
+  /**
+   * Performs DFS while filling h, par, and cost.
+   * @param v root of the tree
+   */
+  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;
+
+    for (int i = 1; i < MAXLOG; ++i)
+      if (par[v][i - 1] != -1) {
+        par[v][i] = par[par[v][i - 1]][i - 1];
+        //* cost[v][i] += cost[v][i - 1] + cost[par[v][i - 1]][i - 1];
+        //** cost[v][i] = max(cost[v][i], max(cost[par[v][i-1]][i-1], cost[v][i-1]));
+      }
+
+    for (auto u : graph[v]) 
+      if (p != u.fi)
+        dfs(u.fi, v, u.se);
+  }
+
+  /**
+   * Preprocess tree.
+   * @param v root of the tree
+   */
+  void preprocess(int v) {
+    mset(par, -1);
+    //*** mset(cost, 0;
+    dfs(v);
+  }
+
+  /**
+   * Returns LCA (or sum or max).
+   * @param p,q query nodes 
+   */
+  int query(int p, int q) {
+    //*** int ans = 0;
+
+    if (h[p] < h[q])
+      swap(p, q);
+
+    for (int i = MAXLOG - 1; i >= 0; --i)
+      if (par[p][i] != -1 && h[par[p][i]] >= h[q]) {
+        //* ans += cost[p][i];
+        //** ans = max(ans, cost[p][i]);
+        p = par[p][i];
+      }
+
+    if (p == q)
+      return p; //*** return ans;
+
+    for (int i = MAXLOG - 1; i >= 0; --i)
+      if (par[p][i] != -1 && par[p][i] != par[q][i]) {
+        //* ans += cost[p][i] + cost[q][i];
+        //** ans = max(ans, max(cost[p][i], cost[q][i]));
+        p = par[p][i];
+        q = par[q][i];
+      }
+
+    //* if (p == q) return ans;
+    //* else return ans + cost[p][0] + cost[q][0];
+
+    //** if (p == q) return ans;
+    //** else return max(ans, max(cost[p][0], cost[q][0]));
+
+    return par[p][0];
+  }
+};
diff --git a/algorithms/graph/prim.cpp b/algorithms/graph/prim.cpp
index 264d509975f7a0676830e966c809f08ec454d0fc..308367ce2c6bdbbad98fb0a2a71f711e1d0a374d 100644
--- a/algorithms/graph/prim.cpp
+++ b/algorithms/graph/prim.cpp
@@ -5,38 +5,50 @@
  * Complexity (Space): O(V + E)
  */
 
-bool cont[MAX];
 vector<ii> graph[MAX];
 
-/**
- * Returns value of MST of graph.
- */
-int prim() {
-  mset(cont, false);
-  cont[0] = true;
-
-  // Add negative values to pq in order to give priority
-  // to the edge with the smallest weight
-  priority_queue<ii> pq;
-  for (auto i : graph[0])
-    pq.push(ii(-i.se, -i.fi));
-
-  // At each step, connect vertex with smallest weight to the MST
-  int ans = 0;
-  while (!pq.empty()) {
-    ii front = pq.top(); pq.pop();
-    int u = -front.se;
-    int w = -front.fi;
-
-    if (!cont[u]) {
-      ans += w;
-      cont[u] = true;
-
-      for (auto i : graph[u])
-        if (!cont[i.fi])
-          pq.push(ii(-i.se, -i.fi));
-    }
+struct Prim {
+  int N;
+  vector<int> vis;
+
+  Prim(int N) :
+    N(N), vis(N)
+  {}
+
+  void init() {
+    fill(all(vis), 0);
   }
 
-  return ans;
-}
+  /**
+   * Returns value of MST of graph.
+   */
+  int run() {
+    init();
+    vis[0] = true;
+
+    // Add negative values to pq in order to give priority
+    // to the edge with the smallest weight
+    priority_queue<ii> pq;
+    for (auto i : graph[0])
+      pq.push(ii(-i.se, -i.fi));
+
+    // At each step, connect vertex with smallest weight to the MST
+    int ans = 0;
+    while (!pq.empty()) {
+      ii front = pq.top(); pq.pop();
+      int u = -front.se;
+      int w = -front.fi;
+
+      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 8c6799cb97005532b954055169062d2d216ca10d..e390a760e50e6c215f3b641cc905315be2c9c8d4 100644
--- a/algorithms/graph/tarjan.cpp
+++ b/algorithms/graph/tarjan.cpp
@@ -5,76 +5,80 @@
  * Complexity (Space): O(V + E)
  */
 
-stack<int> S;
 vector<int> graph[MAX];
 
-int ncomp, ind;
-int visited[MAX];
-
-// The id of a node x (id[x]) is the order in which x was visited in the DFS
-int id[MAX];
-
-// The low-link value of a node x (low[x]) is defined as the smallest id
-// of another node reachable from x when doing a DFS
-int low[MAX];
-
 // scc[i] contains the i-th SCC stored as a vector with the ids of the
 // vertices in it
 vector<int> scc[MAX];
 
-/**
- * Fills SCC with strongly connected components of graph.
- * @param x any vertex
- */
-void dfs(int x) {
-  id[x] = low[x] = ind++;
-  visited[x] = 1;
-
-  S.push(x);
+struct Tarjan {
+  int N, ncomp, ind;
 
-  for (auto i : graph[x])
-    if (id[i] == -1) {
-      dfs(i);
+  stack<int> S;
+  vector<int> vis, id, low;
 
-      // After the DFS, low[i] might have changed, in that case, low[x]
-      // should be updated if a lower value has been found
-      low[x] = min(low[x], low[i]);
+  Tarjan(int N) :
+    N(N), vis(N), id(N), low(N)
+  {}
 
-    // If i has been visited, then i is "above" (has smaller id then x), 
-    // meaning that the edge (x,i) is a "back edge"
-    } else if (visited[i])
-      low[x] = min(low[x], id[i]);
-
-  // A SCC was found
-  if (low[x] == id[x]) {
-    int w;
-
-    // Every node on top of x in the stack belongs to the SCC found
-    do {
-      w = S.top(); S.pop();
-      visited[w] = 0;
-      scc[ncomp].pb(w);
-    } while (w != x);
+  void init() {
+    fill(all(id), -1);
+    fill(all(vis), 0);
+  }
 
-    ncomp++;
+  /**
+   * Fills SCC with strongly connected components of graph.
+   * @param x any vertex
+   */
+  void dfs(int x) {
+    id[x] = low[x] = ind++;
+    vis[x] = 1;
+
+    S.push(x);
+
+    for (auto i : graph[x])
+      if (id[i] == -1) {
+        dfs(i);
+
+        // After the DFS, low[i] might have changed, in that case, low[x]
+        // should be updated if a lower value has been found
+        low[x] = min(low[x], low[i]);
+
+        // If i has been visited, then i is "above" (has smaller id then x), 
+        // meaning that the edge (x,i) is a "back edge"
+      } else if (vis[i])
+        low[x] = min(low[x], id[i]);
+
+    // A SCC was found
+    if (low[x] == id[x]) {
+      int w;
+
+      // Every node on top of x in the stack belongs to the SCC found
+      do {
+        w = S.top(); S.pop();
+        vis[w] = 0;
+        scc[ncomp].pb(w);
+      } while (w != x);
+
+      ncomp++;
+    }
   }
-}
 
-/**
- * Returns number of SCCs.
- * @param n number of vertices
- */
-int tarjan(int n) {
-  mset(id, -1);
-  ncomp = ind = 0;
+  /**
+   * Returns number of SCCs.
+   */
+  int run() {
+    init();
+    ncomp = ind = 0;
 
-  for (int i = 0; i < n; ++i)
-    scc[i].clear();
+    for (int i = 0; i < N; ++i)
+      scc[i].clear();
 
-  // Apply tarjan in every component
-  for (int i = 0; i < n; ++i)
-    if (id[i] == -1)
-      dfs(i);
+    // Apply tarjan in every component
+    for (int i = 0; i < N; ++i)
+      if (id[i] == -1)
+        dfs(i);
 
-  return ncomp;
-}
+    return ncomp;
+  }
+};
diff --git a/algorithms/graph/topological_sort.cpp b/algorithms/graph/topological_sort.cpp
index 508b30e5cec840471360033beeda5692325b4cc7..ed3459ee4be31853d396fee5278e1507ea1df1a1 100644
--- a/algorithms/graph/topological_sort.cpp
+++ b/algorithms/graph/topological_sort.cpp
@@ -5,51 +5,62 @@
  * Complexity (Space): O(V + E)
  */
 
-stack<int> S;
 vector<int> graph[MAX];
 
-int cont[MAX];
+struct TopologicalSort {
+  int N;
+  stack<int> S;
+  vector<int> cont;
 
-/**
- * Fills stack and check for cycles.
- * @param x any vertex
- */
-bool dfs(int x) {
-  cont[x] = 1;
+  Topological(int N) :
+    N(N), cont(N)
+  {}
 
-  for (auto i : graph[x]) {
-    if (cont[i] == 1)
-      return true;
-    if (!cont[i] && dfs(i))
-      return true;
+  void init() {
+    fill(all(cont), 0);
   }
 
-  cont[x] = 2;
-  S.push(x);
+  /**
+   * Fills stack and check for cycles.
+   * @param x any vertex
+   */
+  bool dfs(int x) {
+    cont[x] = 1;
 
-  return false;
-}
+    for (auto i : graph[x]) {
+      if (cont[i] == 1)
+        return true;
+      if (!cont[i] && dfs(i))
+        return true;
+    }
 
-/** 
- * Returns whether graph contains cycle or not.
- * @param n number of vertices
- * @param[out] tsort topological sort of the graph
- */
-bool topological_sort(int n, vector<int> &tsort) {
-  mset(cont, 0);
-  
-  bool cycle = false;
-  for (int i = 0; i < n; ++i)
-    if (!cont[i])
-      cycle |= dfs(i);
-
-  if (cycle)
-    return true;
-
-  while (!S.empty()) {
-    tsort.pb(S.top());
-    S.pop();
+    cont[x] = 2;
+    S.push(x);
+
+    return false;
   }
 
-  return false;
-}
+  /** 
+   * Returns whether graph contains cycle or not.
+   * @param[out] tsort topological sort of the graph
+   */
+  bool topological_sort(vector<int> &tsort) {
+    init();
+
+    bool cycle = false;
+    for (int i = 0; i < N; ++i) {
+      if (!cont[i])
+        cycle |= dfs(i);
+    }
+
+    if (cycle)
+      return true;
+
+    while (!S.empty()) {
+      tsort.pb(S.top());
+      S.pop();
+    }
+
+    return false;
+  }
+};
diff --git a/algorithms/math/fft.cpp b/algorithms/math/fft.cpp
index 1e8a541450e4ec1d62d4cf96706091cc7ceb21df..cc105a48219ce42328afa9ec3a831200f48b1d42 100644
--- a/algorithms/math/fft.cpp
+++ b/algorithms/math/fft.cpp
@@ -5,126 +5,119 @@
  * Complexity (Space): O(N)
  */
 
-struct comp {
-  float r, i;
 
-  comp() : r(0), i(0) {}
-  comp(float r, float i) : r(r), i(i) {}
+struct FFT {
+  struct Complex {
+    float r, i;
 
-  comp operator+(comp b) { 
-    return comp(r + b.r, i + b.i); 
-  }
-
-  comp operator-(comp b) {
-    return comp(r - b.r, i - b.i);
-  }
+    Complex() : r(0), i(0) {}
+    Complex(float r, float i) : r(r), i(i) {}
 
-  comp operator*(comp b) {
-    return comp(r * b.r - i * b.i, r * b.i + i * b.r);
-  }
+    Complex operator+(Complex b) { return Complex(r + b.r, i + b.i); }
+    Complex operator-(Complex b) { return Complex(r - b.r, i - b.i); }
+    Complex operator*(Complex b) { return Complex(r*b.r - i*b.i, r*b.i + i*b.r); }
 
-  comp operator/(comp b) {
-    float div = (b.r * b.r) + (b.i * b.i);
-    return comp((r * b.r + i * b.i) / div, (i * b.r - r * b.i) / div);
-  }
-};
-
-
-// Returns complex conjugate
-inline comp conj(comp a) {
-  return comp(a.r, -a.i);
-}
+    Complex operator/(Complex b) {
+      float div = (b.r * b.r) + (b.i * b.i);
+      return Complex((r * b.r + i * b.i) / div, (i * b.r - r * b.i) / div);
+    }
 
-vector<int> rev = {0, 1};
-vector<comp> roots = {{0, 0}, {1, 0}};
+    // Returns complex conjugate
+    static inline Complex conj(Complex a) { return Complex(a.r, -a.i); }
+  };
 
+  vector<int> rev = {0, 1};
+  vector<Complex> roots = {{0, 0}, {1, 0}};
 
-// Initializes reversed-bit vector (rev) and roots of unity vector (roots)
-void init(int nbase) {
-  rev.resize(1 << nbase);
-  roots.resize(1 << nbase);
+  /**
+   * Initializes reversed-bit vector (rev) and roots of unity vector (roots)
+   * @param nbase log2 of size of vectors.
+   */
+  void init(int nbase) {
+    rev.resize(1 << nbase);
+    roots.resize(1 << nbase);
 
-  // Construct rev vector
-  for (int i = 0; i < (1 << nbase); ++i)
-    rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
+    // Construct rev vector
+    for (int i = 0; i < (1 << nbase); ++i)
+      rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
 
-  // Construct roots vector
-  for (int base = 1; base < nbase; ++base) {
-    float angle = 2 * M_PI / (1 << (base + 1));
+    // Construct roots vector
+    for (int base = 1; base < nbase; ++base) {
+      float angle = 2 * M_PI / (1 << (base + 1));
 
-    for (int i = 1 << (base - 1); i < (1 << base); ++i) {
-      float angle_i = angle * (2 * i + 1 - (1 << base));
+      for (int i = 1 << (base - 1); i < (1 << base); ++i) {
+        float angle_i = angle * (2 * i + 1 - (1 << base));
 
-      roots[i << 1] = roots[i];
-      roots[(i << 1) + 1] = comp(cos(angle_i), sin(angle_i));
+        roots[i << 1] = roots[i];
+        roots[(i << 1) + 1] = Complex(cos(angle_i), sin(angle_i));
+      }
     }
   }
-}
-
 
-// Applies FFT on vector a
-void fft(vector<comp> &a) {
-  int n = a.size();
-
-  // Change order of elements to match the end of recursion
-  for (int i = 0; i < n; ++i)
-    if (i < rev[i])
-      swap(a[i], a[rev[i]]);
-
-  // Iterate through "recursion tree"
-  for (int s = 1; s < n; s <<= 1) {
-
-    // Iterate through all pairs of vectors (tree leaves)
-    for (int k = 0; k < n; k += (s << 1)) {
-
-      // Execute "combine step"
-      for (int j = 0; j < s; ++j) {
-        comp z = a[k + j + s] * roots[j + s];
-
-        a[k + j + s] = a[k + j] - z;
-        a[k + j] = a[k + j] + z;
+  /**
+   * Applies FFT on a vector.
+   * @param a input vector
+   */
+  void fft(vector<Complex> &a) {
+    int n = a.size();
+
+    // Change order of elements to match the end of recursion
+    for (int i = 0; i < n; ++i)
+      if (i < rev[i])
+        swap(a[i], a[rev[i]]);
+
+    for (int s = 1; s < n; s <<= 1) {
+      for (int k = 0; k < n; k += (s << 1)) {
+        for (int j = 0; j < s; ++j) {
+          Complex z = a[k + j + s] * roots[j + s];
+          a[k + j + s] = a[k + j] - z;
+          a[k + j] = a[k + j] + z;
+        }
       }
     }
   }
-}
 
+  /**
+   * Executes vector multiplication in O(n log n).
+   * @param a, b input vectors
+   */
+  vector<int> multiply(const vector<int> &a, const vector<int> &b) {
+    int nbase, need = a.size() + b.size() + 1;
 
-// Multiplies vectors a and b using FFT
-vector<int> multiply(vector<int> &a, vector<int> &b) {
-  int nbase, need = a.size() + b.size() + 1;
+    for (nbase = 0; (1 << nbase) < need; ++nbase);
+    init(nbase);
 
-  for (nbase = 0; (1 << nbase) < need; ++nbase);
-  init(nbase);
+    int size = 1 << nbase;
+    vector<Complex> fa(size);
 
-  int size = 1 << nbase;
-  vector<comp> fa(size);
+    // Assemble vector fa from a and b
+    for (int i = 0; i < size; ++i) {
+      int x = (i < a.size() ? a[i] : 0);
+      int y = (i < b.size() ? b[i] : 0);
+      fa[i] = Complex(x, y);
+    }
 
-  // Assemble vector fa from a and b
-  for (int i = 0; i < size; ++i) {
-    int x = (i < a.size() ? a[i] : 0);
-    int y = (i < b.size() ? b[i] : 0);
-    fa[i] = comp(x, y);
-  }
+    fft(fa);
 
-  fft(fa);
+    // Multiply vectors using magic
+    Complex r(0, -0.25 / size);
+    for (int i = 0; i <= (size >> 1); ++i) {
+      int j = (size - i) & (size - 1);
+      Complex z = (fa[j] * fa[j] - conj(fa[i] * fa[i])) * r;
 
-  // Multiply vectors using magic
-  comp r(0, -0.25 / size);
-  for (int i = 0; i <= (size >> 1); ++i) {
-    int j = (size - i) & (size - 1);
-    comp z = (fa[j] * fa[j] - conj(fa[i] * fa[i])) * r;
+      if (i != j)
+        fa[j] = (fa[i] * fa[i] - conj(fa[j] * fa[j])) * r;
 
-    if (i != j)
-      fa[j] = (fa[i] * fa[i] - conj(fa[j] * fa[j])) * r;
-    fa[i] = z;
-  }
+      fa[i] = z;
+    }
 
-  fft(fa);
+    fft(fa);
 
-  // Obtain result vector
-  vector<int> res(need);
-  for (int i = 0; i < need; ++i)
-    res[i] = fa[i].r + 0.5;
+    // Obtain result vector
+    vector<int> res(need);
+    for (int i = 0; i < need; ++i)
+      res[i] = fa[i].r + 0.5;
 
-  return res;
-}
+    return res;
+  }
+};
diff --git a/algorithms/math/matrix.cpp b/algorithms/math/matrix.cpp
index 951517043c4af58afd163791b6d4e49002ad5cf7..f33351a79b7e3c6b55222f8f5daf8ab6d00e782d 100644
--- a/algorithms/math/matrix.cpp
+++ b/algorithms/math/matrix.cpp
@@ -18,7 +18,7 @@ struct matrix {
   matrix operator*(matrix a) {
     assert(r == a.c && c == a.r);
 
-    matrix res(r, c);
+    Matrix res(r, c);
     for (int i = 0; i < r; i++)
       for (int j = 0; j < c; j++) {
         res[i][j] = 0;
@@ -30,8 +30,8 @@ struct matrix {
     return res;
   }
 
-  matrix operator+(matrix a) {
-    matrix res(k);
+  Matrix operator+(Matrix a) {
+    Matrix res(k);
     for (int i = 0; i < r; ++i)
       for (int j = 0; j < c; ++j)
         res[i][j] = m[i][j] + a[i][j];
diff --git a/algorithms/math/sieve_of_eratosthenes.cpp b/algorithms/math/sieve_of_eratosthenes.cpp
index 8e25be7cb27830c80d277d67fcf4c2be8d7645ec..64b926851767b39791cfdd2dae49600b7e87a9c3 100644
--- a/algorithms/math/sieve_of_eratosthenes.cpp
+++ b/algorithms/math/sieve_of_eratosthenes.cpp
@@ -8,20 +8,36 @@
 /**
  * Returns vector of primes less than or equal to n
  */
-vector<int> sieve(int n) {
-  vector<int> primes;
-  vector<bool> is_prime(n+1, true);
+struct Sieve {
+  int N;
+  vector<int> is_prime;
 
-  // Mark which elements are not prime (multiples of p)
-  for (int p = 2; p*p <= n; ++p)
-    if (is_prime[p])
-      for (int i = p*p; i <= n; i += p)
-        is_prime[i] = false;
+  Sieve(int N) :
+    N(N), is_prime(N + 1)
+  {}
 
-  // Add non-marked elements (primes) to the list
-  for (int p = 2; p <= n; ++p)
-    if (is_prime[p])
-      primes.pb(p);
+  void init() {
+    fill(all(is_prime), 1);
+  }
 
-  return primes;
-}
+  /**
+   * Returns vector of primes less than N
+   */
+  vector<int> run() {
+    vector<int> primes;
+    init();
+
+    // Mark which elements are not prime (multiples of p)
+    for (int p = 2; p*p <= N; ++p)
+      if (is_prime[p])
+        for (int i = p*p; i <= N; i += p)
+          is_prime[i] = false;
+
+    // Add non-marked elements (primes) to the list
+    for (int p = 2; p <= N; ++p)
+      if (is_prime[p])
+        primes.pb(p);
+
+    return primes;
+  }
+};
diff --git a/algorithms/paradigm/kadane.cpp b/algorithms/paradigm/kadane.cpp
index b5fba6795af5b2155bdc44d9593b3394679148f3..627a3f2ea14a274a0f1f4c6acdc3abcd4d98150b 100644
--- a/algorithms/paradigm/kadane.cpp
+++ b/algorithms/paradigm/kadane.cpp
@@ -12,10 +12,11 @@
  */
 int kadane(const vector<int> &v, int &start, int &end) {
 
+  int n = v.size(), s = 0;
+  start = end = 0;
+
   // Maximum so far (msf), Maximum ending here (meh).
   int msf = -0x3f3f3f3f, meh = 0;
-  int s = 0;
-  start = end = 0;
 
   for (int i = 0; i < n; ++i) {
     meh += v[i];
diff --git a/algorithms/string/kmp.cpp b/algorithms/string/kmp.cpp
index 6158db09b25782b5ce4f1c09b3364231fed9931b..80cbf8123a6c019c93b846eae210dea32fa830af 100644
--- a/algorithms/string/kmp.cpp
+++ b/algorithms/string/kmp.cpp
@@ -10,7 +10,8 @@
 int table[MAX];
 
 /**
- * Builds the table where table[i] is the longest prefix of patt[0..i] which is
+ * Builds the table where table[i] is the longest prefix of
+ * patt[0..i] which is
  * also a sufix of patt[0..i]
  * @param patt pattern to be found
  */
@@ -28,7 +29,8 @@ void preprocess(string patt) {
 }
 
 /**
- * Searches for occurrences of patt in txt and add indexes of matches to occurs
+ * Searches for occurrences of patt in txt and add indexes of 
+ * matches to occurs
  * @param patt pattern to be found
  * @param txt text
  */
@@ -41,6 +43,7 @@ void search(string patt, string txt) {
       i++, j++;
 
     if (j == patt.size()) {
+
       // Pattern found at (i - j)
       occurs.push_back(i - j);
       j = table[j - 1];
diff --git a/algorithms/structure/avl.cpp b/algorithms/structure/avl.cpp
index 0dbff66c05fa9a7a92270f4960e9f2474d59d603..2fa017ce3b18ff7a7ea1eb9407ce2fcdefee711d 100644
--- a/algorithms/structure/avl.cpp
+++ b/algorithms/structure/avl.cpp
@@ -5,120 +5,142 @@
  * Complexity (Space): O(n)
  */
 
-struct avl_node_t {
-  int key;
-  int size;    // number of nodes bellow (optional)
-  int height;  // height of node
-
-  avl_node_t *left;
-  avl_node_t *right;
-};
-
-
-struct avl_t {
-  avl_node_t *root;
-};
+struct AVL {
+  struct Node {
+    int key, size, height;
+    Node *left, *right;
+
+    Node(int key, int size, int height) :
+      key(key), size(size), height(height),
+      left(nullptr), right(nullptr)
+    {}
+
+    /**
+     * Change height based on the information on the left and right.
+     */
+    void fix_height() {
+      int lh = (left == nullptr) ? 0 : left->height;
+      int rh = (right == nullptr) ? 0 : right->height;
+      height = max(lh, rh) + 1;
+    }
+
+    /**
+     * Change size based on the information on the left and right.
+     */
+    void fix_size() {
+      int ls = (left == nullptr) ? 0 : left->size;
+      int rs = (right == nullptr) ? 0 : right->size;
+      size = ls + rs + 1;
+    }
+
+    /**
+     * Fix both height and size.
+     */
+    void fix_state() {
+      fix_height();
+      fix_size();
+    }
+
+    /**
+     * Returns difference between the height on the left and the 
+     * height on the right
+     */
+    int get_balance() {
+      int lh = (left == nullptr) ? 0 : left->height;
+      int rh = (right == nullptr) ? 0 : right->height;
+      return lh - rh;
+    }
+  };
+
+  Node *root;
+
+  AVL() : 
+    root(nullptr) 
+  {}
+
+  /**
+   * Rotates node to right.
+   * @param node input node 
+   */
+  Node *rotate_right(Node *node) {
+    Node *aux1 = node->left;
+    Node *aux2 = aux1->right;
+
+    aux1->right = node;
+    node->left = aux2;
+
+    node->fix_state();
+    aux1->fix_state();
+
+    return aux1;
+  }
 
-/**
- * Returns height of node.
- */
-inline int get_height(avl_node_t *node) {
-  return (node == NULL) ? 0 : node->height;
-}
+  /**
+   * Rotates node to left.
+   * @param node input node 
+   */
+  Node *rotate_left(Node *node) {
+    Node *aux1 = node->right;
+    Node *aux2 = aux1->left;
 
-/**
- * Returns size of node.
- */
-inline int get_size(avl_node_t *node) {
-  return (node == NULL) ? 0 : node->size;
-}
+    aux1->left = node;
+    node->right = aux2;
 
-/**
- * Returns balance of node.
- */
-inline int get_balance(avl_node_t *node) {
-  return (node == NULL) ? 0 : get_height(node->left) - get_height(node->right);
-}
+    node->fix_state();
+    aux1->fix_state();
 
-/**
- * Rotates node to right.
- */
-avl_node_t *rotate_right(avl_node_t *node) {
-  avl_node_t *aux1 = node->left;
-  avl_node_t *aux2 = aux1->right;
+    return aux1;
+  }
 
-  aux1->right = node;
-  node->left = aux2;
+  /**
+   * Inserts key recursively in AVL and returns new root.
+   * @param node root
+   * @param key value to be inserted
+   */
+  Node *insert(Node *node, int key) {
+    if (node == nullptr) {
 
-  node->height = max(get_height(node->left), get_height(node->right)) + 1;
-  aux1->height = max(get_height(aux1->left), get_height(aux1->right)) + 1;
+      // Create new node
+      Node *new_node = new Node(key, 1, 1);
+      if (root == nullptr)
+        root = new_node;
 
-  node->size = get_size(node->left) + get_size(node->right) + 1;
-  aux1->size = get_size(aux1->left) + get_size(aux1->right) + 1;
-  
-  return aux1;
-}
+      return new_node;
+    }
 
-/**
- * Rotates node to left.
- */
-avl_node_t *rotate_left(avl_node_t *node) {
-  avl_node_t *aux1 = node->right;
-  avl_node_t *aux2 = aux1->left;
+    // Insert recursively
+    if (key < node->key)
+      node->left  = insert(node->left, key);
+    else
+      node->right = insert(node->right, key);
 
-  aux1->left = node;
-  node->right = aux2;
+    int balance = node->get_balance();
+    node->fix_state();
 
-  node->height = max(get_height(node->left), get_height(node->right)) + 1;
-  aux1->height = max(get_height(aux1->left), get_height(aux1->right)) + 1;
+    // Check balance of tree and rotates if necessary
+    if (balance > 1 && key < node->left->key) {
+      return rotate_right(node);
 
-  node->size = get_size(node->left) + get_size(node->right) + 1;
-  aux1->size = get_size(aux1->left) + get_size(aux1->right) + 1;
-  
-  return aux1;
-}
+    } else if (balance < -1 && key > node->right->key) {
+      return rotate_left(node);
 
-/**
- * Inserts key in AVL and returns new root.
- */
-avl_node_t *avl_insert(avl_t *avl, avl_node_t *node, int key) {
-  if (node == NULL) {
-
-    // Create new node
-    avl_node_t *neu = new avl_node_t;
-
-    neu->key = key;
-    neu->left = neu->right = NULL;
-    neu->height = neu->size = 1;
+    } else if (balance > 1 && key > node->left->key) {
+      node->left = rotate_left(node->left);
+      return rotate_right(node);
 
-    if (avl->root == NULL)
-      avl->root = neu;
+    } else if (balance < -1 && key < node->right->key) {
+      node->right = rotate_right(node->right);
+      return rotate_left(node);
+    }
 
-    return neu;
+    return node;
   }
 
-  // Insert recursively
-  if (key < node->key)
-    node->left  = avl_insert(avl, node->left, key);
-  else
-    node->right = avl_insert(avl, node->right, key);
-
-  int balance = get_balance(node);
-  node->height = max(get_height(node->left), get_height(node->right)) + 1;
-  node->size   = get_size(node->left) + get_size(node->right) + 1;
-
-  // Check balance of tree and rotates if necessary
-  if (balance > 1 && key < node->left->key) {
-    return rotate_right(node);
-  } else if (balance < -1 && key > node->right->key) {
-    return rotate_left(node);
-  } else if (balance > 1 && key > node->left->key) {
-    node->left = rotate_left(node->left);
-    return rotate_right(node);
-  } else if (balance < -1 && key < node->right->key) {
-    node->right = rotate_right(node->right);
-    return rotate_left(node);
+  /**
+   * Insert new key.
+   * @param key value to be inserted
+   */
+  void insert(int key) {
+    root = insert(root, key);
   }
-
-  return node;
-}
+};
diff --git a/algorithms/structure/ball_tree.cpp b/algorithms/structure/ball_tree.cpp
index 361a572784fba2b3858d3df9604b19f7d71d761d..3f07ed6eaa2a633435eb5ac99666a13d41429190 100644
--- a/algorithms/structure/ball_tree.cpp
+++ b/algorithms/structure/ball_tree.cpp
@@ -8,173 +8,179 @@
 #define x first
 #define y second
 
-typedef pair<double, double> point;
-typedef vector<point> pset;
 
-struct node {
-  double radius;
-  point center;
+struct BallTree {
+  typedef pair<double, double> point;
 
-  node *left, *right;
-};
+  struct Node {
+    double radius;
+    point center;
 
-/**
- * Returns distance between point a and b
- */
-double distance(point &a, point &b) {
-  return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
-}
+    Node *left, *right;
+  };
 
-/**
- * Finds furthest point from center and returns <distance,index> of that point
- */
-pair<double, int> get_radius(point &center, pset &ps) {
-  int ind = 0;
-  double dist, radius = -1.0;
 
-  for (int i = 0; i < ps.size(); ++i) {
-    dist = distance(center, ps[i]);
-
-    if (radius < dist) {
-      radius = dist;
-      ind = i;
-    }
+  BallTree(vector<point> &points) {
+    build(points);
   }
 
-  return pair<double, int>(radius, ind);
-}
-
-/**
- * Finds average point and pretends it's the center of the given set of points
- * @param ps vector of points 
- * @param[out] center center point
- */
-void get_center(const pset &ps, point &center) {
-  center.x = center.y = 0;
-
-  for (auto p : ps) {
-    center.x += p.x;
-    center.y += p.y;
+  /**
+   * Returns distance between point a and b
+   */
+  double distance(point &a, point &b) {
+    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
   }
 
-  center.x /= (double) ps.size();
-  center.y /= (double) ps.size();
-}
-
-/**
- * Splits the set of points in closer to ps[lind] and closer to ps[rind],
- * where lind is returned by get_radius and rind is the furthest points
- * from ps[lind]
- * @param ps vector of points
- * @param[out] left leftmost point
- * @param[out] right rightmost point
- * @param lind index of left point
- */
-void partition(const pset &ps, pset &left, pset &right, int lind) {
-  int rind = 0;
-  double dist, grt = -1.0;
-  double ldist, rdist;
-
-  point rmpoint;
-  point lmpoint = ps[lind];
+  /**
+   * Finds furthest point from center and returns <distance,index> of that point
+   */
+  pair<double, int> get_radius(point &center, vector<point> &ps) {
+    int ind = 0;
+    double dist, radius = -1.0;
 
-  for (int i = 0; i < ps.size(); ++i)
-    if (i != lind) {
-      dist = distance(lmpoint, ps[i]);
+    for (int i = 0; i < ps.size(); ++i) {
+      dist = distance(center, ps[i]);
 
-      if (dist > grt) {
-        grt = dist;
-        rind = i;
+      if (radius < dist) {
+        radius = dist;
+        ind = i;
       }
     }
 
-  rmpoint = ps[rind];
-
-  left.push_back(ps[lind]);
-  right.push_back(ps[rind]);
-
-  for (int i = 0; i < ps.size(); ++i)
-    if (i != lind && i != rind) {
-      ldist = distance(ps[i], lmpoint);
-      rdist = distance(ps[i], rmpoint);
+    return pair<double, int>(radius, ind);
+  }
 
-      if (ldist <= rdist)
-        left.push_back(ps[i]);
-      else
-        right.push_back(ps[i]);
+  /**
+   * Finds average point and pretends it's the center of the given set of points
+   * @param ps vector of points 
+   * @param[out] center center point
+   */
+  void get_center(const vector<point> &ps, point &center) {
+    center.x = center.y = 0;
+
+    for (auto p : ps) {
+      center.x += p.x;
+      center.y += p.y;
     }
-}
-
-/**
- * Builds ball-tree recursively.
- * @param ps vector of points
- */
-node *build(pset &ps) {
-  if (ps.size() == 0)
-    return nullptr;
 
-  node *n = new node;
+    center.x /= (double) ps.size();
+    center.y /= (double) ps.size();
+  }
 
-  // When there's only one point in ps, a leaf node is created storing that
-  // point
-  if (ps.size() == 1) {
-    n->center = ps[0];
+  /**
+   * Splits the set of points in closer to ps[lind] and closer to ps[rind],
+   * where lind is returned by get_radius and rind is the furthest points
+   * from ps[lind]
+   * @param ps vector of points
+   * @param[out] left leftmost point
+   * @param[out] right rightmost point
+   * @param lind index of left point
+   */
+  void partition(const vector<point> &ps, vector<point> &left, vector<point> &right, int lind) {
+    int rind = 0;
+    double dist, grt = -1.0;
+    double ldist, rdist;
+
+    point rmpoint;
+    point lmpoint = ps[lind];
+
+    for (int i = 0; i < ps.size(); ++i)
+      if (i != lind) {
+        dist = distance(lmpoint, ps[i]);
+
+        if (dist > grt) {
+          grt = dist;
+          rind = i;
+        }
+      }
 
-    n->radius = 0.0;
-    n->right = n->left = nullptr;
+    rmpoint = ps[rind];
 
-  // Otherwise, ps gets split into two partitions, one for each child
-  } else {
-    get_center(ps, n->center);
-    auto rad = get_radius(n->center, ps);
+    left.push_back(ps[lind]);
+    right.push_back(ps[rind]);
 
-    pset lpart, rpart;
-    partition(ps, lpart, rpart, rad.second);
+    for (int i = 0; i < ps.size(); ++i)
+      if (i != lind && i != rind) {
+        ldist = distance(ps[i], lmpoint);
+        rdist = distance(ps[i], rmpoint);
 
-    n->radius = rad.first;
-    n->left = build(lpart);
-    n->right = build(rpart);
+        if (ldist <= rdist)
+          left.push_back(ps[i]);
+        else
+          right.push_back(ps[i]);
+      }
   }
 
-  return n;
-}
+  /**
+   * Builds ball-tree recursively.
+   */
+  Node *build(vector<point> &ps) {
+    if (ps.size() == 0)
+      return nullptr;
 
-/**
- * Search the ball-tree recursively
- * @param n root
- * @param t query point
- * @param pq initially empty multiset (will contain the answer after execution)
- * @param k number of nearest neighbors
- */
-void search(node *n, point t, multiset<double> &pq, int &k) {
-  if (n->left == nullptr && n->right == nullptr) {
-    double dist = distance(t, n->center);
+    Node *n = new Node;
+
+    // When there's only one point in ps, a leaf node is created storing that
+    // point
+    if (ps.size() == 1) {
+      n->center = ps[0];
 
-    // (!) Only necessary when the same point needs to be ignored
-    if (dist < EPS)
-      return;
+      n->radius = 0.0;
+      n->right = n->left = nullptr;
+
+      // Otherwise, ps gets split into two partitions, one for each child
+    } else {
+      get_center(ps, n->center);
+      auto rad = get_radius(n->center, ps);
 
-    else if (pq.size() < k || dist < *pq.rbegin()) {
-      pq.insert(dist);
+      vector<point> lpart, rpart;
+      partition(ps, lpart, rpart, rad.second);
 
-      if (pq.size() > k)
-        pq.erase(prev(pq.end()));
+      n->radius = rad.first;
+      n->left = build(lpart);
+      n->right = build(rpart);
     }
-  } else {
-    double distl = distance(t, n->left->center);
-    double distr = distance(t, n->right->center);
 
-    if (distl <= distr) {
-      if (pq.size() < k || (distl <= *pq.rbegin() + n->left->radius))
-        search(n->left, t, pq, k);
-      if (pq.size() < k || (distr <= *pq.rbegin() + n->right->radius))
-        search(n->right, t, pq, k);
+    return n;
+  }
 
+  /**
+   * Search the ball-tree recursively
+   * @param n root
+   * @param t query point
+   * @param pq initially empty multiset (will contain the answer after execution)
+   * @param k number of nearest neighbors
+   */
+  void search(Node *n, point t, multiset<double> &pq, int &k) {
+    if (n->left == nullptr && n->right == nullptr) {
+      double dist = distance(t, n->center);
+
+      // (!) Only necessary when the same point needs to be ignored
+      if (dist < EPS)
+        return;
+
+      else if (pq.size() < k || dist < *pq.rbegin()) {
+        pq.insert(dist);
+
+        if (pq.size() > k)
+          pq.erase(prev(pq.end()));
+      }
     } else {
-      if (pq.size() < k || (distr <= *pq.rbegin() + n->right->radius))
-        search(n->right, t, pq, k);
-      if (pq.size() < k || (distl <= *pq.rbegin() + n->left->radius))
-        search(n->left, t, pq, k);
+      double distl = distance(t, n->left->center);
+      double distr = distance(t, n->right->center);
+
+      if (distl <= distr) {
+        if (pq.size() < k || (distl <= *pq.rbegin() + n->left->radius))
+          search(n->left, t, pq, k);
+        if (pq.size() < k || (distr <= *pq.rbegin() + n->right->radius))
+          search(n->right, t, pq, k);
+
+      } else {
+        if (pq.size() < k || (distr <= *pq.rbegin() + n->right->radius))
+          search(n->right, t, pq, k);
+        if (pq.size() < k || (distl <= *pq.rbegin() + n->left->radius))
+          search(n->left, t, pq, k);
+      }
     }
   }
-}
+};
diff --git a/algorithms/structure/bit.cpp b/algorithms/structure/bit.cpp
index 35ad665e0ecdd5333e2819f35a3faa6aab33973c..30e645c83d676b17d51848bd726349ef37e2a10f 100644
--- a/algorithms/structure/bit.cpp
+++ b/algorithms/structure/bit.cpp
@@ -7,23 +7,34 @@
  * Complexity (Space): O(n)
  */
 
-int tree[MAX];
+struct BIT {
+  int N;
+  vector<int> tree;
 
-/**
- * Performs query in array (tree) in the idx position.
- */
-int query(int idx) {
-  int sum = 0;
-  for (; idx > 0; idx -= (idx & -idx))
-    sum += tree[idx];
+  BIT(int N) :
+    N(N), tree(N)
+  {}
 
-  return sum;
-}
+  void init() {
+    fill(all(tree), 0);
+  }
 
-/**
- * Adds a value (val) to a single position (idx) in the array (tree).
- */
-void update(int idx, int val) {
-  for (; idx <= MAX; idx += (idx & -idx))
-    tree[idx] += val;
-}
+  /**
+   * Performs query in array (tree) in the idx position.
+   */
+  int query(int idx) {
+    int sum = 0;
+    for (; idx > 0; idx -= (idx & -idx))
+      sum += tree[idx];
+
+    return sum;
+  }
+
+  /**
+   * Adds a value (val) to a single position (idx) in the array (tree).
+   */
+  void update(int idx, int val) {
+    for (; idx < N; idx += (idx & -idx))
+      tree[idx] += val;
+  }
+};
diff --git a/algorithms/structure/bit2d.cpp b/algorithms/structure/bit2d.cpp
index 68dca491c1d5e1188649318ea87b09cf1133f9e8..d8ce41ea8233cdc3c231627ee0dbe05288698695 100644
--- a/algorithms/structure/bit2d.cpp
+++ b/algorithms/structure/bit2d.cpp
@@ -7,25 +7,37 @@
  * Complexity (Space): O(n^2)
  */
 
-int tree[MAXN][MAXM];
+struct BIT2D {
+  int N, M;
+  vector<vector<int>> tree;
 
-/**
- * Performs query in array (tree) in the (idx,idy) position.
- */
-int query(int idx, int idy) {
-  int sum = 0;
-  for (; idx > 0; idx -= (idx & -idx))
-    for (int m = idy; m > 0; m -= (m & -m))
-      sum += tree[idx][m];
+  BIT2D(int N, int M) :
+    N(N), M(M), tree(N, vector<int>(M))
+  {}
 
-  return sum;
-}
+  void init() {
+    for (auto &i : tree)
+      fill(all(i), 0);
+  }
 
-/** 
- * Adds a value (val) to a single position (idx,idy) in the array (tree).
- */
-void update(int idx, int idy, int val) {
-  for (; idx <= MAXN; idx += (idx & -idx))
-    for (int m = idy; m <= MAXM; m += (m & -m))
-      tree[idx][m] += val;
-}
+  /**
+   * Performs query in array (tree) in the (idx,idy) position.
+   */
+  int query(int idx, int idy) {
+    int sum = 0;
+    for (; idx > 0; idx -= (idx & -idx))
+      for (int m = idy; m > 0; m -= (m & -m))
+        sum += tree[idx][m];
+
+    return sum;
+  }
+
+  /** 
+   * Adds a value (val) to a single position (idx,idy) in the array (tree).
+   */
+  void update(int idx, int idy, int val) {
+    for (; idx < N; idx += (idx & -idx))
+      for (int m = idy; m < M; m += (m & -m))
+        tree[idx][m] += val;
+  }
+};
diff --git a/algorithms/structure/bitmask.cpp b/algorithms/structure/bitmask.cpp
index 2ce620293c3610b93af9b0c4b77213b6fc7db481..2506f97d14e0e8296a2fff444db88d1f6ab5677f 100644
--- a/algorithms/structure/bitmask.cpp
+++ b/algorithms/structure/bitmask.cpp
@@ -5,51 +5,59 @@
  * Complexity (Space): O(1)
  */
 
-/**
- * Sets bit in position pos (0 to 1).
- */
-void set(ll &bitmask, int pos) { 
-  bitmask |= (1 << pos); 
-}
+struct Bitmask {
+  ll state;
 
-/**
- * Sets all bits in a bitmask with size n.
- */
-void set_all(ll &bitmask, int n) { 
-  bitmask = (1 << n) - 1; 
-}
+  Bitmask(ll state) :
+    state(state)
+  {}
 
-/**
- * Unsets bit in position pos (1 to 0).
- */
-void unset(ll &bitmask, int pos) { 
-  bitmask &= ~(1 << pos); 
-}
+  /**
+   * Sets bit in position pos (0 to 1).
+   */
+  void set(int pos) { 
+    state |= (1 << pos); 
+  }
 
-/**
- * Unsets all bits.
- */
-void unset_all(ll &bitmask) { 
-  bitmask = 0; 
-}
+  /**
+   * Sets all bits in a bitmask with size n.
+   */
+  void set_all(int n) { 
+    state = (1 << n) - 1; 
+  }
 
-/**
- * Gets value of bit in position pos.
- */
-int get(ll bitmask, int pos) { 
-  return bitmask & (1 << pos); 
-}
+  /**
+   * Unsets bit in position pos (1 to 0).
+   */
+  void unset(int pos) { 
+    state &= ~(1 << pos); 
+  }
 
-/**
- * Toggles value in position pos.
- */
-void toggle(ll &bitmask, int pos) { 
-  bitmask ^= (1 << pos); 
-}
+  /**
+   * Unsets all bits.
+   */
+  void unset_all() { 
+    state = 0; 
+  }
 
-/**
- * Gets position of least significant 1.
- */
-int least_significant_one(ll bitmask) {
-  return bitmask & (-bitmask); 
-}
+  /**
+   * Gets value of bit in position pos.
+   */
+  int get(int pos) { 
+    return state & (1 << pos); 
+  }
+
+  /**
+   * Toggles value in position pos.
+   */
+  void toggle(int pos) { 
+    state ^= (1 << pos); 
+  }
+
+  /**
+   * Gets position of least significant 1.
+   */
+  int least_significant_one() {
+    return state & (-state); 
+  }
+};
diff --git a/algorithms/structure/disjoint_set.cpp b/algorithms/structure/disjoint_set.cpp
index d9f943999c96c56bf7781bd43026cba972f2352a..59a9a4741b96ad05a421a93ad1e154c88caa8e4a 100644
--- a/algorithms/structure/disjoint_set.cpp
+++ b/algorithms/structure/disjoint_set.cpp
@@ -8,44 +8,49 @@
  * Complexity (Space): O(n)
  */
 
-int h[MAX];
-int par[MAX];
-int size[MAX];
-
-/**
- * Initializes element x.
- */
-void make_set(int x) {
-  par[x] = x;
-  h[x] = 0;
-  size[x] = 1;
-}
-
-/**
- * Returns set index from element x.
- */
-int find_set(int x) {
-  if (par[x] != x)
-    par[x] = find_set(par[x]);
-  return par[x];
-}
-
-/**
- * Makes x and y belong to the same set.
- */
-void union_set(int x, int y) {
-  x = find_set(x);
-  y = find_set(y);
-
-  if (x == y)
-    return;
-
-  if (h[x] > h[y])
-    swap(x, y);
-
-  par[x] = y;
-  size[y] += size[x];
-
-  if (h[x] == h[y])
-    h[x]++;
-}
+struct DisjointSet {
+  int N;
+  vector<int> h, par, size;
+
+  Disjoint(int N) :
+    N(N), h(N), par(N), size(N)
+  {}
+
+  /**
+   * Initializes element x.
+   */
+  void make_set(int x) {
+    par[x] = x;
+    h[x] = 0;
+    size[x] = 1;
+  }
+
+  /**
+   * Returns set index from element x.
+   */
+  int find_set(int x) {
+    if (par[x] != x)
+      par[x] = find_set(par[x]);
+    return par[x];
+  }
+
+  /**
+   * Makes x and y belong to the same set.
+   */
+  void union_set(int x, int y) {
+    x = find_set(x);
+    y = find_set(y);
+
+    if (x == y)
+      return;
+
+    if (h[x] > h[y])
+      swap(x, y);
+
+    par[x] = y;
+    size[y] += size[x];
+
+    if (h[x] == h[y])
+      h[x]++;
+  }
+};
diff --git a/algorithms/structure/lazy_segment_tree.cpp b/algorithms/structure/lazy_segment_tree.cpp
index a159d3f297278d194e1ba64878e030e4def9d856..fced1ab2ff81f3f0128e164c477a57de8d1df18a 100644
--- a/algorithms/structure/lazy_segment_tree.cpp
+++ b/algorithms/structure/lazy_segment_tree.cpp
@@ -8,85 +8,97 @@
  * Complexity (Space): O(n)
  */
 
-int N;
-int v[MAX];
-int tree[4 * MAX], lazy[4 * MAX];
+struct LazySegmentTree {
+  int N;
+  vector<int> tree, lazy;
 
-#define left(x) (x << 1)
-#define right(x) ((x << 1) + 1)
-
-/**
- * Builds tree with elements from v (0-indexed).
- */
-void build(int node = 1, int a = 0, int b = N - 1) {
-  if (a > b) 
-    return;
-
-  if (a == b) {
-    tree[node] = v[a];
-    return;
+  LazySegmentTree(int N, const vector<int> &v) : N(N), tree(N*4), lazy(N*4) {
+    init();
+    build(v);
   }
 
-  build(left(node), a, (a + b) / 2);
-  build(right(node), (a + b) / 2 + 1, b);
-  tree[node] = tree[node * 2] + tree[node * 2 + 1];
-}
-
-/**
- * Propagates value to tree and through lazy tree.
- * @param node node to change
- * @param a,b range of node
- * @param val value to be pushed 
- */
-void push(int node, int a, int b, int val) {
-  tree[node] += val;
-  // tree[node] += (b - a + 1) * val; (for Range Sum Query)
-
-  if (a != b) {
-    lazy[left(node)] += val;
-    lazy[right(node)] += val;
+  void init() {
+    fill(all(tree), 0);
+    fill(all(lazy), 0);
   }
 
-  lazy[node] = 0;
-}
-
-/**
- * Updates segment [i,j] by adding value val.
- * @param i,j range
- * @param val value to be added
- */
-void update(int i, int j, int val, int node = 1, int a = 0, int b = N - 1) {
-  if (lazy[node] != 0)
-    push(node, a, b, lazy[node]);
-
-  if (a > b || a > j || b < i) 
-    return;
+  inline int left(int x) { return (x << 1); }
+  inline int right(int x) { return (x << 1) + 1; }
+
+  /**
+   * Builds tree with elements from v (0-indexed).
+   * @param v vector containing initial values
+   */
+  void build(const vector<int> &v, int node = 1, int a = 0, int b = N - 1) {
+    if (a > b) 
+      return;
+
+    if (a == b) {
+      tree[node] = v[a];
+      return;
+    }
+
+    build(v, left(node), a, (a + b) / 2);
+    build(v, right(node), (a + b) / 2 + 1, b);
+    tree[node] = tree[node * 2] + tree[node * 2 + 1];
+  }
 
-  if (i <= a && b <= j) {
-    push(node, a, b, val);
-    return;
+  /**
+   * Propagates value to tree and through lazy tree.
+   * @param node node to change
+   * @param a,b range of node
+   * @param val value to be pushed 
+   */
+  void push(int node, int a, int b, int val) {
+    tree[node] += val;
+    // tree[node] += (b - a + 1) * val; (for Range Sum Query)
+
+    if (a != b) {
+      lazy[left(node)] += val;
+      lazy[right(node)] += val;
+    }
+
+    lazy[node] = 0;
   }
 
-  update(i, j, val, left(node), a, (a + b) / 2);
-  update(i, j, val, right(node), (a + b) / 2 + 1, b);
-  tree[node] = tree[node * 2] + tree[node * 2 + 1];
-}
+  /**
+   * Updates segment [i,j] by adding value val.
+   * @param i,j range
+   * @param val value to be added
+   */
+  void update(int i, int j, int val, int node = 1, int a = 0, int b = N - 1) {
+    if (lazy[node] != 0)
+      push(node, a, b, lazy[node]);
+
+    if (a > b || a > j || b < i) 
+      return;
+
+    if (i <= a && b <= j) {
+      push(node, a, b, val);
+      return;
+    }
+
+    update(i, j, val, left(node), a, (a + b) / 2);
+    update(i, j, val, right(node), (a + b) / 2 + 1, b);
+    tree[node] = tree[node * 2] + tree[node * 2 + 1];
+  }
 
-/**
- * Returns sum of [i,j].
- * @param i,j range
- */
-int query(int i, int j, int node = 1, int a = 0, int b = N - 1) {
-  if (a > b || a > j || b < i)
-    return 0;
+  /**
+   * Returns sum of [i,j].
+   * @param i,j range
+   */
+  int query(int i, int j, int node = 1, int a = 0, int b = N - 1) {
+    if (a > b || a > j || b < i)
+      return 0;
 
-  if (lazy[node])
-    push(node, a, b, lazy[node]);
+    if (lazy[node])
+      push(node, a, b, lazy[node]);
 
-  if (a >= i && b <= j)
-    return tree[node];
+    if (a >= i && b <= j)
+      return tree[node];
 
-  int q1 = query(i, j, left(node), a, (a + b) / 2);
-  int q2 = query(i, j, right(node), (a + b) / 2 + 1, b);
-  return q1 + q2;
-}
+    int q1 = query(i, j, left(node), a, (a + b) / 2);
+    int q2 = query(i, j, right(node), (a + b) / 2 + 1, b);
+    return q1 + q2;
+  }
+};
diff --git a/algorithms/structure/policy_tree.cpp b/algorithms/structure/policy_tree.cpp
index e6d7770029bbf6d093ca819c25e8309e3762ab10..16c53941de22b85ee75580416df49828e03d8932 100644
--- a/algorithms/structure/policy_tree.cpp
+++ b/algorithms/structure/policy_tree.cpp
@@ -16,7 +16,13 @@
 
 using namespace __gnu_pbds;
 
-typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> set_t;
+typedef tree<
+  int, 
+  null_type, 
+  less<int>, 
+  rb_tree_tag, 
+  tree_order_statistics_node_update
+> set_t;
 
 /**
  * Demonstration of operations.
diff --git a/algorithms/structure/segment_tree.cpp b/algorithms/structure/segment_tree.cpp
index 9152accaaf4952c42b491c92a2533ef1fd18f746..7ffed8fe40fe2032c8976597f5920a478f5bd906 100644
--- a/algorithms/structure/segment_tree.cpp
+++ b/algorithms/structure/segment_tree.cpp
@@ -8,61 +8,72 @@
  * Complexity (Space): O(n)
  */
 
-int N;
-int v[MAX];
-int tree[4 * MAX];
+struct SegmentTree {
+  int N;
+  vector<int> tree;
 
-#define left(x) (x << 1)
-#define right(x) ((x << 1) + 1)
-
-/**
- * Builds tree with elements from v (0-indexed).
- */
-void build(int node = 1, int a = 0, int b = N - 1) {
-  if (a > b) 
-    return;
+  SegmentTree(int N, const vector<int> &v) : N(N), tree(N*4) {
+    init();
+    build(v);
+  }
 
-  if (a == b) {
-    tree[node] = v[a];
-    return;
+  void init() {
+    fill(all(tree), 0);
   }
 
-  build_tree(left(node), a, (a + b) / 2);
-  build_tree(right(node), 1 + (a + b) / 2, b);
-  tree[node] = tree[node * 2] + tree[node * 2 + 1];
-}
+  inline int left(int x) { return (x << 1); }
+  inline int right(int x) { return (x << 1) + 1; }
 
-/**
- * Updates position idx by adding value val.
- * @param idx position
- * @param val value to be added
- */
-void update(int idx, int val, int node = 1, int a = 0, int b = N - 1) {
-  if (a > b || a > idx || b < idx) 
-    return;
+  /**
+   * Builds tree with elements from v (0-indexed).
+   * @param v vector containing initial values
+   */
+  void build(const vector<int> &v, int node = 1, int a = 0, int b = N - 1) {
+    if (a > b) 
+      return;
+
+    if (a == b) {
+      tree[node] = v[a];
+      return;
+    }
 
-  if (a == b) {
-    tree[node] = val;
-    return;
+    build(v, left(node), a, (a + b) / 2);
+    build(v, right(node), 1 + (a + b) / 2, b);
+    tree[node] = tree[node * 2] + tree[node * 2 + 1];
   }
 
-  update_tree(idx, val, left(node), a, (a + b) / 2);
-  update_tree(idx, val, right(node), 1 + (a + b) / 2, b);
-  tree[node] = tree[node * 2] + tree[node * 2 + 1];
-}
+  /**
+   * Updates position idx by adding value val.
+   * @param idx position
+   * @param val value to be added
+   */
+  void update(int idx, int val, int node = 1, int a = 0, int b = N - 1) {
+    if (a > b || a > idx || b < idx) 
+      return;
 
-/**
- * Returns sum of [i,j].
- * @param i,j range
- */
-int query(int i, int j, int node = 1, int a = 0, int b = N - 1) {
-  if (a > b || a > j || b < i) 
-    return 0;
+    if (a == b) {
+      tree[node] = val;
+      return;
+    }
+
+    update(idx, val, left(node), a, (a + b) / 2);
+    update(idx, val, right(node), 1 + (a + b) / 2, b);
+    tree[node] = tree[node * 2] + tree[node * 2 + 1];
+  }
+
+  /**
+   * Returns sum of [i,j].
+   * @param i,j range
+   */
+  int query(int i, int j, int node = 1, int a = 0, int b = N - 1) {
+    if (a > b || a > j || b < i) 
+      return 0;
 
-  if (i <= a && b <= j) 
-    return tree[node];
+    if (i <= a && b <= j) 
+      return tree[node];
 
-  int q1 = query_tree(i, j, left(node), a, (a + b) / 2);
-  int q2 = query_tree(i, j, right(node), 1 + (a + b) / 2, b);
-  return q1 + q2;
-}
+    int q1 = query(i, j, left(node), a, (a + b) / 2);
+    int q2 = query(i, j, right(node), 1 + (a + b) / 2, b);
+    return q1 + q2;
+  }
+};
diff --git a/algorithms/structure/trie.cpp b/algorithms/structure/trie.cpp
index 979afb6d1c18b050a25adab990c11754136b9a05..4bae5fc141930b7f2e7c999b6c1319c258bf32ad 100644
--- a/algorithms/structure/trie.cpp
+++ b/algorithms/structure/trie.cpp
@@ -8,83 +8,107 @@
  */
 
 // ========== Trie for String ==========
-int states = 0;
-int trie[MAX][26]; // mset(-1)
+struct Trie {
+  int N, states;
+
+  // ending[i] is true when the node i represents the last
+  // char of a string contained in the Trie
+  vector<int> ending;
+  vector<vector<int>> trie;
+
+  Trie(int N) :
+    N(N), ending(N), trie(N, vector<int>(26))
+  { init(); }
+
+  void init() {
+    state = 0;
+    for (auto &i : trie)
+      fill(all(i), -1);
+  }
 
-// ending[i] is true when the node i represents the last
-// character of a string contained in the Trie
-bool ending[MAX];
+  /**
+   * Inserts word into the Trie.
+   */
+  void insert(string word) {
+    int node = 0;
 
-/**
- * Inserts word into the Trie.
- */
-void insert(string word) {
-  int node = 0;
+    for (int i = 0; i < word.size(); ++i) {
+      int b = word[i] - 'a';
 
-  for (int i = 0; i < word.size(); ++i) {
-    int b = word[i] - 'a';
+      if (trie[node][b] == -1)
+        trie[node][b] = ++states;
+      node = trie[node][b];
+    }
 
-    if (trie[node][b] == -1)
-      trie[node][b] = ++states;
-    node = trie[node][b];
+    ending[node] = true;
   }
 
-  ending[node] = true;
-}
+  /**
+   * Returns true if word is in the Trie.
+   */
+  bool search(string word) {
+    int node = 0;
 
-/**
- * Returns true if word is in the Trie.
- */
-bool search(string word) {
-  int node = 0;
+    for (int i = 0; i < word.size(); ++i) {
+      node = trie[node][word[i] - 'a'];
+      if (node == -1)
+        return false;
+    }
 
-  for (int i = 0; i < word.size(); ++i) {
-    node = trie[node][word[i] - 'a'];
-    if (node == -1)
-      return false;
+    return ending[node];
   }
-
-  return ending[node];
-}
+};
 
 
 // ========== Trie for Integer ==========
-int states = 0;
-int trie[MAX][2]; // mset(-1)
+struct Trie {
+  int N, states;
+
+  // ending[i] is true when the node i represents the last
+  // bit of an integer contained in the Trie
+  vector<int> ending;
+  vector<vector<int>> trie;
+
+  Trie(int N) :
+    N(N), ending(N), trie(N, vector<int>(2))
+  {}
+
+  void init() {
+    states = 0;
+    for (auto &i : trie)
+      fill(all(i), -1);
+  }
 
-// ending[i] is true when the node i represents the last
-// bit of an integer contained in the Trie
-bool ending[MAX];
+  /**
+   * Inserts x into the Trie.
+   */
+  void insert(int x) {
+    int node = 0;
 
-/**
- * Inserts x into the Trie.
- */
-void insert(int x) {
-  int node = 0;
+    for (int i = 30; i >= 0; --i) {
+      int b = !!(x & (1 << i));
 
-  for (int i = 30; i >= 0; --i) {
-    int b = !!(x & (1 << i));
+      if (trie[node][b] == -1)
+        trie[node][b] = ++states;
+      node = trie[node][b];
+    }
 
-    if (trie[node][b] == -1)
-      trie[node][b] = ++states;
-    node = trie[node][b];
+    ending[node] = true;
   }
 
-  ending[node] = true;
-}
+  /** 
+   * Returns true if x is in the Trie.
+   */
+  bool search(int x) {
+    int node = 0;
 
-/** 
- * Returns true if x is in the Trie.
- */
-bool search(int x) {
-  int node = 0;
-  
-  for (int i = 30; i >= 0; --i) {
-    int b = !!(x & (1 << i));
-    node = trie[node][b];
-    if (node == -1)
-      return false;
-  }
+    for (int i = 30; i >= 0; --i) {
+      int b = !!(x & (1 << i));
+      node = trie[node][b];
+      if (node == -1)
+        return false;
+    }
 
-  return ending[node];
-}
+    return ending[node];
+  }
+};
diff --git a/contests/Cadernaveis/ENGARRAF.cpp b/contests/Cadernaveis/ENGARRAF.cpp
index cb45af832dc09f57767c8aface65465ff60022e5..589978139de7ff4b1447d447dbca49af175a4852 100644
--- a/contests/Cadernaveis/ENGARRAF.cpp
+++ b/contests/Cadernaveis/ENGARRAF.cpp
@@ -21,38 +21,48 @@ using namespace std;
 typedef long long ll;
 typedef pair<int,int> ii;
 
-int dist[MAX];
 vector<ii> graph[MAX];
 
-int dijkstra(int o, int d) {
-  set<ii> pq;
-  int u, v, wt;
+struct Dijkstra {
+  int N;
+  vector<int> dist, vis;
 
-  mset(dist, inf);
+  Dijkstra(int N) :
+    N(N), dist(N), vis(N)
+  {}
 
-  dist[o] = 0;
-  pq.insert(ii(0, o));
+  void init() {
+    fill(all(dist), inf);
+    fill(all(vis), 0);
+  }
+
+  int run(int s, int d) {
+    set<ii> pq;
+
+    dist[s] = 0;
+    pq.insert(ii(0, s));
 
-  while (pq.size() != 0) {
-    u = pq.begin()->second;
-    pq.erase(pq.begin());
+    while (pq.size() != 0) {
+      int u = pq.begin()->se;
+      pq.erase(pq.begin());
 
-    for (auto i : graph[u]) {
-      v = i.first;
-      wt = i.second;
+      if (vis[u]) continue;
+      vis[u] = 1;
 
-      if (dist[v] > dist[u] + wt) {
-        if (dist[v] != inf)
-          pq.erase(pq.find(ii(dist[v], v)));
+      for (auto i : graph[u]) {
+        int v = i.fi;
+        int wt = i.se;
 
-        dist[v] = dist[u] + wt;
-        pq.insert(ii(dist[v], v));
+        if (!vis[v] && dist[v] > dist[u] + wt) {
+          dist[v] = dist[u] + wt;
+          pq.insert(ii(dist[v], v));
+        }
       }
     }
-  }
 
-  return dist[d];
-}
+    return dist[d];
+  }
+} dijkstra(MAX);
 
 int main() {
   ios::sync_with_stdio(0);
@@ -60,7 +70,9 @@ int main() {
 
   int n, m;
   while (cin >> n >> m && (n || m)) {
-    for (int i = 1; i <= n; ++i) graph[i].clear();
+    dijkstra.init();
+    for (int i = 0; i <= n; ++i)
+      graph[i].clear();
 
     for (int i = 0; i < m; ++i) {
       int o, d, t; cin >> o >> d >> t;
@@ -68,7 +80,7 @@ int main() {
     }
 
     int s, t; cin >> s >> t;
-    int ans = dijkstra(s, t);
+    int ans = dijkstra.run(s, t);
     cout << ((ans == inf) ? -1 : ans) << ende;
   }
 
diff --git a/contests/Cadernaveis/URI1850.cpp b/contests/Cadernaveis/URI1850.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e169ec3198d47d73b3b4064f609f2d52dc5897ac
--- /dev/null
+++ b/contests/Cadernaveis/URI1850.cpp
@@ -0,0 +1,100 @@
+#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; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+typedef pair<ll, int> lli;
+typedef pair<ii, lli> elem;
+
+ll cont[110][110];
+int dx[] = {1, -1, 0, 0};
+int dy[] = {0, 0, 1, -1};
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  string x;
+  vector<string> v;
+
+  int n, m;
+  ii arya, exit;
+  for (int lin = 0; cin >> x; ++lin) {
+    v.pb(x);
+    for (int i = 0; i < x.size(); ++i) {
+      if (x[i] == '@')
+        arya = {lin, i};
+      else if (x[i] == '*')
+        exit = {lin, i};
+    }
+
+    n = lin;
+    m = x.size();
+  }
+  n++;
+
+  mset(cont, -1);
+
+  queue<elem> Q;
+  Q.push({arya, {0LL, 0}});
+  int ans = -1;
+
+  while (!Q.empty()) {
+    elem curr = Q.front(); Q.pop();
+    cont[curr.fi.fi][curr.fi.se] = curr.se.fi;
+
+    //for (int i = 0; i < n; ++i) {
+    //  for (int j = 0; j < m; ++j)
+    //    cout << cont[i][j] << " ";
+    //  cout << ende;
+    //}
+    //cout << ende;
+
+
+    if (curr.fi == exit) {
+      ans = curr.se.se;
+      break;
+    }
+
+    for (int i = 0; i < 4; ++i) {
+      int x = curr.fi.fi + dx[i];
+      int y = curr.fi.se + dy[i];
+
+      if (x >= 0 && x < n && y >= 0 && y < m && (cont[x][y] == -1 || __builtin_popcountll(cont[x][y]) < __builtin_popcountll(curr.se.fi)) && v[x][y] != '#') {
+        ll msk = curr.se.fi;
+
+        if (v[x][y] >= 'a' && v[x][y] <= 'g') {
+          msk |= (1 << (v[x][y] - 'a'));
+        }
+
+        if (v[x][y] >= 'A' && v[x][y] <= 'G') {
+          if (msk & (1 << (v[x][y] - 'A')))
+            Q.push({{x, y}, {msk, curr.se.se + 1}});
+        } else
+          Q.push({{x, y}, {msk, curr.se.se + 1}});
+      }
+    }
+  }
+
+  if (ans == -1)
+    cout << "--" << ende;
+  else
+    cout << ans << ende;
+
+  return 0;
+}
diff --git a/contests/Cadernaveis/UVA10594.cpp b/contests/Cadernaveis/UVA10594.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8a5b115e381cc538ffaf056ff7edee7eb68d4cd9
--- /dev/null
+++ b/contests/Cadernaveis/UVA10594.cpp
@@ -0,0 +1,90 @@
+#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; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+int N;
+int par[MAX];
+int graph[MAX][MAX], rg[MAX][MAX];
+
+bool cont[MAX];
+
+
+bool bfs(int s, int t) {
+  queue<int> Q;
+  Q.push(s);
+  cont[s] = true;
+
+  while (!Q.empty()) {
+    int u = Q.front(); Q.pop();
+
+    // Sink was found, there is a path
+    if (u == t)
+      return true;
+
+    for (int i = 0; i < N; ++i)
+      if (!cont[i] && rg[u][i]) {
+        cont[i] = true;
+        par[i] = u;
+        Q.push(i);
+      }
+  }
+
+  return false;
+}
+
+int edmonds_karp(int s, int t) {
+  int ans = 0;
+  par[s] = -1;
+
+  mset(cont, 0);
+  memcpy(rg, graph, sizeof(graph));
+
+  while (bfs(s, t)) {
+    int flow = inf;
+
+    for (int i = t; par[i] != -1; i = par[i])
+      flow = min(flow, rg[par[i]][i]);
+
+    for (int i = t; par[i] != -1; i = par[i]) {
+      rg[par[i]][i] -= flow;
+      rg[i][par[i]] += flow;
+    }
+
+    ans += flow;
+    mset(cont, 0);
+  }
+
+  return ans;
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, m;
+  while (cin >> n >> m) {
+    for (int i = 0; i < m; ++i) {
+      int a, b, c; cin >> a >> b >> c;
+      
+    }
+  }
+
+  return 0;
+}
diff --git a/contests/CodeJam/2018/Round 1A/A/in b/contests/CodeJam/2018/Round 1A/A/in
new file mode 100644
index 0000000000000000000000000000000000000000..1d7239047690506fa9ec6908899f42ed70c631e9
--- /dev/null
+++ b/contests/CodeJam/2018/Round 1A/A/in	
@@ -0,0 +1,28 @@
+6
+3 6 1 1
+.@@..@
+.....@
+@.@.@@
+4 3 1 1
+@@@
+@.@
+@.@
+@@@
+4 5 1 1
+.....
+.....
+.....
+.....
+4 4 1 1
+..@@
+..@@
+@@..
+@@..
+3 4 2 2
+@.@@
+@@.@
+@.@@
+3 4 1 2
+.@.@
+@.@.
+.@.@
diff --git a/contests/CodeJam/2018/Round 1A/A/solve.cpp b/contests/CodeJam/2018/Round 1A/A/solve.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d3436ee1d699b474a173a1f1380f6e86a01be066
--- /dev/null
+++ b/contests/CodeJam/2018/Round 1A/A/solve.cpp	
@@ -0,0 +1,95 @@
+#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; 
+
+typedef long long ll;
+typedef pair<int,int> ii;
+
+int sum[101][101];
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int t; cin >> t;
+  for (int cas = 1; cas <= t; ++cas) {
+    int r, c, h, v; cin >> r >> c >> h >> v;
+
+    int choc = 0;
+    vector<string> waff(r);
+    for (auto &i : waff) {
+      cin >> i;
+      for (auto j : i) 
+        choc += (j == '@');
+    }
+
+    int per_r = choc / (h+1);
+    int per_c = choc / (v+1);
+
+    mset(sum, 0);
+    for (int i = 0; i < c; ++i)
+      sum[0][i] = (waff[0][i] == '@');
+    for (int i = 1; i < r; ++i)
+      for (int j = 0; j < c; ++j)
+        sum[i][j] = sum[i-1][j] + (waff[i][j] == '@');
+    for (int i = 0; i < r; ++i)
+      for (int j = 1; j < c; ++j)
+        sum[i][j] += sum[i][j-1];
+
+    vector<int> rcut;
+    for (int i = 0; i < r; ++i) {
+      int val = sum[i][c-1];
+      if (rcut.size() > 0)
+        val -= sum[rcut.back()][c-1];
+      if (val == per_r)
+        rcut.pb(i);
+    }
+
+    vector<int> ccut;
+    for (int i = 0; i < c; ++i) {
+      int val = sum[r-1][i];
+      if (ccut.size() > 0)
+        val -= sum[r-1][ccut.back()];
+      if (val == per_c)
+        ccut.pb(i);
+    }
+
+    bool poss = true;
+    if ((rcut.size() != (h+1) || ccut.size() != (v+1)) && choc != 0)
+      poss = false;
+
+    if (poss && choc != 0) {
+      for (int i = 0; i < h+1; ++i) {
+        for (int j = 0; j < v+1; ++j) {
+          int cnt = 0;
+          for (int ii = ((i==0) ? (0) : (rcut[i-1]+1)); ii <= rcut[i]; ++ii)
+            for (int jj = ((j==0) ? (0) : (ccut[j-1]+1)); jj <= ccut[j]; ++jj)
+              cnt += (waff[ii][jj] == '@');
+          if (cnt != (choc / ((h+1)*(v+1))))
+            poss = false;
+        }
+      }
+    }
+
+    cout << "Case #" << cas << ": ";
+    if (poss) cout << "POSSIBLE" << ende;
+    else cout << "IMPOSSIBLE" << ende;
+  }
+
+
+  return 0;
+}
diff --git a/contests/ICPC_SA17/C.cpp b/contests/ICPC_LA17/C.cpp
similarity index 100%
rename from contests/ICPC_SA17/C.cpp
rename to contests/ICPC_LA17/C.cpp
diff --git a/contests/ICPC_SA17/E.cpp b/contests/ICPC_LA17/E.cpp
similarity index 100%
rename from contests/ICPC_SA17/E.cpp
rename to contests/ICPC_LA17/E.cpp
diff --git a/contests/ICPC_SA17/H.cpp b/contests/ICPC_LA17/H.cpp
similarity index 100%
rename from contests/ICPC_SA17/H.cpp
rename to contests/ICPC_LA17/H.cpp
diff --git a/contests/ICPC_SA17/I.cpp b/contests/ICPC_LA17/I.cpp
similarity index 100%
rename from contests/ICPC_SA17/I.cpp
rename to contests/ICPC_LA17/I.cpp
diff --git a/contests/ICPC_SA17/J.cpp b/contests/ICPC_LA17/J.cpp
similarity index 100%
rename from contests/ICPC_SA17/J.cpp
rename to contests/ICPC_LA17/J.cpp
diff --git a/contests/ICPC_LA18/A.cpp b/contests/ICPC_LA18/A.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a044d3562ca72cb0cc97d678f273087b0e4bc556
--- /dev/null
+++ b/contests/ICPC_LA18/A.cpp
@@ -0,0 +1,34 @@
+#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.erase(s.begin() + s.size() - 3);
+  stringstream x(s);
+  int r; x >> r;
+  cout << 36000 / __gcd(36000, r) << ende;
+
+  return 0;
+}
diff --git a/contests/ICPC_LA18/B.cpp b/contests/ICPC_LA18/B.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af4e17d4693d8ada8ad58068950664265245aa63
--- /dev/null
+++ b/contests/ICPC_LA18/B.cpp
@@ -0,0 +1,53 @@
+#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), pref(n);
+  for (auto &i : v) cin >> i;
+
+  pref[0] = v[0];
+  for (int i = 1; i < n; ++i)
+    pref[i] = pref[i-1] + v[i];
+
+  if (pref.back() % 2) 
+    return cout << "N" << ende, 0;
+
+  int beg = 0;
+  vector<ii> found;
+  for (int i = 0; i < n; ++i) {
+    while (beg < i && pref[i] - pref[beg] > pref.back() / 2)
+      beg++;
+
+    if (pref[i] - pref[beg] == (pref.back() / 2))
+      found.pb(ii(beg, i));
+  }
+
+  if (found.size() >= 2)
+    cout << "Y" << ende;
+  else
+    cout << "N" << ende;
+
+  return 0;
+}
diff --git a/contests/ICPC_LA18/C.cpp b/contests/ICPC_LA18/C.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf661800c5ca044e4c401e55ddb650caebff233d
--- /dev/null
+++ b/contests/ICPC_LA18/C.cpp
@@ -0,0 +1,66 @@
+#include <bits/stdc++.h>
+
+#define MAX 10101
+#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 n;
+int d[MAX], c[MAX];
+int dp[MAX][6][123];
+
+int fix(int x) {
+  if (x > 120) return 121;
+  else return x;
+}
+
+int solve(int i, int state, int mi) {
+  if (i == n)
+    return 0;
+
+  if (dp[i][state][mi] != -1)
+    return dp[i][state][mi];
+
+  if (state == 0 || mi >= 120)
+    return dp[i][state][mi] = solve(i + 1, 1, fix(d[i])) + c[i];
+
+  if (state == 1)
+    return dp[i][state][mi] = 
+      min(solve(i + 1, state + 1, fix(mi + d[i])) + (c[i] / 2),
+          solve(i + 1, 1, fix(d[i])) + c[i]);
+  else
+    return dp[i][state][mi] = 
+      min(solve(i + 1, (state + 1) % 6, fix(mi + d[i])) + (c[i] / 4),
+          solve(i + 1, 1, fix(d[i])) + c[i]);
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  cin >> n;
+  for (int i = 0; i < n; ++i) {
+    cin >> d[i] >> c[i];
+    c[i] *= 100;
+  }
+
+  mset(dp, -1);
+  int ans = solve(0, 0, 0);
+  cout << (ans / 100) << "." << setfill('0') << setw(2) << (ans % 100) << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA18/D.py b/contests/ICPC_LA18/D.py
new file mode 100644
index 0000000000000000000000000000000000000000..c536ec00a427e4ecde92c65025c29d09a4e69d3f
--- /dev/null
+++ b/contests/ICPC_LA18/D.py
@@ -0,0 +1,7 @@
+n = int(input())
+every = []
+for i in range(n):
+    s = input()
+    x = s.split('@')
+    every += [ x[0].split('+')[0].replace('.','') + x[1] ]
+print(len(set(every)))
diff --git a/contests/ICPC_LA18/H.cpp b/contests/ICPC_LA18/H.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ffbae8d3b0d62ed82875c81e219dd91c5244470
--- /dev/null
+++ b/contests/ICPC_LA18/H.cpp
@@ -0,0 +1,95 @@
+#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>;
+using iii = pair<ll,ii>;
+
+ii operator+(const ii &a, const ii &b) {
+  return ii(a.fi + b.fi, a.se + b.se);
+}
+
+struct Dijkstra {
+  int N;
+  vector<ll> dist;
+  vector<int> cont;
+  vector<vector<iii>> graph;
+
+  Dijkstra(int N) :
+    N(N), dist(N, llinf), cont(N, 0), graph(N)
+  {}
+
+  ll run(int s) {
+    set<iii> pq;
+
+    ll ans = 0;
+    dist[s] = 0;
+    pq.insert(iii(0, ii(s, 0)));
+
+    while (pq.size() != 0) {
+      iii top = *(pq.begin());
+      pq.erase(pq.begin());
+
+      int u = top.se.fi;
+      if (cont[u])
+        continue;
+
+      cont[u] = 1;
+      ans += top.se.se;
+
+      for (auto i : graph[u]) {
+        int v = i.fi;
+        ll wt = i.se.fi;
+
+        if (!cont[v] && dist[v] >= top.fi + wt) {
+          dist[v] = top.fi + wt;
+          pq.insert(iii(dist[v], ii(v, i.se.se)));
+        }
+      }
+    }
+
+    return ans;
+  } 
+};
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n, m; cin >> n >> m;
+  Dijkstra d(n+2);
+  map<ii,ii> M;
+  for (int i = 0; i < m; ++i) {
+    int a, b; ll l, c; 
+    cin >> a >> b >> l >> c;
+    if (M.find(ii(a, b)) != M.end()) {
+      M[ii(a, b)] = min(M[ii(a, b)], ii(l, c));
+      M[ii(b, a)] = M[ii(a, b)];
+    } else {
+      M[ii(a, b)] = {l, c};
+      M[ii(b, a)] = {l, c};
+    }
+  }
+
+  for (auto i : M)
+    d.graph[i.fi.fi].pb({i.fi.se, i.se});
+
+  ll ans = d.run(1);
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA18/I.cpp b/contests/ICPC_LA18/I.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9724f19cebaee747c2f1f20f9ae78b81dde19c97
--- /dev/null
+++ b/contests/ICPC_LA18/I.cpp
@@ -0,0 +1,63 @@
+#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 par[MAX], deg[MAX], lev[MAX];
+vector<int> graph[MAX];
+
+void dfs(int x, int l) {
+  lev[x] = l;
+  for (auto i : graph[x])
+    dfs(i, l + 1);
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n; cin >> n;
+  for (int i = 2; i <= n; ++i) {
+    int x; cin >> par[i];
+    deg[par[i]]++;
+    graph[par[i]].pb(i);
+  }
+
+  dfs(1, 0);
+  set<ii> S;
+  for (int i = 2; i <= n; ++i)
+    S.insert(ii(-lev[i], i));
+  
+  int ans = 0;
+  while (S.size() > 0) {
+    ii curr = *S.begin();
+    S.erase(S.begin());
+
+    if (deg[curr.se] >= 2 && deg[par[curr.se]] >= 3 && par[curr.se] != 1 && 
+        S.find(ii(-lev[par[curr.se]], par[curr.se])) != S.end()) {
+      S.erase(ii(-lev[par[curr.se]], par[curr.se]));
+      deg[par[par[curr.se]]]--;
+      ans++;
+    }
+  }
+
+  cout << ans << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA18/L.cpp b/contests/ICPC_LA18/L.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..134cd18983eb62544aa60a420c5e6a6ef27b4a2e
--- /dev/null
+++ b/contests/ICPC_LA18/L.cpp
@@ -0,0 +1,120 @@
+#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>;
+using iii = pair<ii,int>;
+
+vector<int> sieve(int n) {
+  vector<int> primes;
+  vector<bool> is_prime(n+1, true);
+
+  for (int p = 2; p*p <= n; ++p)
+    if (is_prime[p])
+      for (int i = p*p; i <= n; i += p)
+        is_prime[i] = false;
+
+  for (int p = 2; p <= n; ++p)
+    if (is_prime[p])
+      primes.pb(p);
+
+  return primes;
+}
+
+int N;
+int v[MAX];
+int tree[4 * MAX];
+
+#define left(x) (x << 1)
+#define right(x) ((x << 1) + 1)
+
+void build(int node = 1, int a = 0, int b = N - 1) {
+  if (a > b) 
+    return;
+
+  if (a == b) {
+    tree[node] = v[a];
+    return;
+  }
+
+  build(left(node), a, (a + b) / 2);
+  build(right(node), 1 + (a + b) / 2, b);
+  tree[node] = tree[node * 2] + tree[node * 2 + 1];
+}
+
+void update(int idx, int val, int node = 1, int a = 0, int b = N - 1) {
+  if (a > b || a > idx || b < idx) 
+    return;
+
+  if (a == b) {
+    tree[node] += val;
+    return;
+  }
+
+  update(idx, val, left(node), a, (a + b) / 2);
+  update(idx, val, right(node), 1 + (a + b) / 2, b);
+  tree[node] = tree[node * 2] + tree[node * 2 + 1];
+}
+
+int query(int i, int j, int node = 1, int a = 0, int b = N - 1) {
+  if (a > b || a > j || b < i) 
+    return 0;
+
+  if (i <= a && b <= j) 
+    return tree[node];
+
+  int q1 = query(i, j, left(node), a, (a + b) / 2);
+  int q2 = query(i, j, right(node), 1 + (a + b) / 2, b);
+  return q1 + q2;
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  vector<int> primes = sieve(100000);
+
+  int q; cin >> q;
+  vector<iii> que(q);
+  for (int i = 0; i < q; ++i) {
+    int n, k; cin >> n >> k;
+    que[i] = {ii(k, n), i};
+  }
+
+  N = 100001;
+  fill(v, v+N, 1);
+  build();
+
+  vector<int> ans(q);
+  int curr = primes.size() - 1;
+  sort(rall(que));
+  for (auto i : que) {
+    while (curr >= 0 && primes[curr] > i.fi.fi) {
+      for (int j = primes[curr]; j <= N; j += primes[curr])
+        if (query(j, j) != 0) update(j, -1);
+      curr--;
+    }
+
+    ans[i.se] = query(2, i.fi.se);
+  }
+
+  for (int i = 0; i < q; ++i)
+    cout << ans[i] << ende;
+  return 0;
+}
diff --git a/contests/ICPC_LA18/M.cpp b/contests/ICPC_LA18/M.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9813471fe693e015ec31e50de7fd2b92197c4e5a
--- /dev/null
+++ b/contests/ICPC_LA18/M.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;
+  int past = 0;
+  int ans = 0;
+  for (int i = 0; i < n; ++i) {
+    int x; cin >> x;
+    if (x > past)
+      ans++;
+    past = x;
+  }
+  cout << ans << ende;
+
+  return 0;
+}
diff --git a/contests/ICPC_LA18/out b/contests/ICPC_LA18/out
new file mode 100644
index 0000000000000000000000000000000000000000..8a7ce29a78a4449142fc2ad93f177deb4f7cb51a
--- /dev/null
+++ b/contests/ICPC_LA18/out
@@ -0,0 +1 @@
+361391
diff --git a/misc/template.cpp b/misc/template.cpp
index c30f33f938d3d06ccd9ef9b570c2760e8179fe3d..c4a76b363a6b6102a3955dd56a441a68df14d155 100644
--- a/misc/template.cpp
+++ b/misc/template.cpp
@@ -16,8 +16,8 @@
 
 using namespace std; 
 
-typedef long long ll;
-typedef pair<int,int> ii;
+using ll = long long;
+using ii = pair<int,int>;
 
 int main() {
   ios::sync_with_stdio(0);