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 ¢er, 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 ¢er) { - 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 ¢er, 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 ¢er) { + 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);