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