diff --git a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Esparsa/seg_tree_sparse.cpp b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Esparsa/seg_tree_sparse.cpp index c1f8ac84..ee292b95 100644 --- a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Esparsa/seg_tree_sparse.cpp +++ b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Esparsa/seg_tree_sparse.cpp @@ -1,4 +1,4 @@ -template +const ll MINL = (ll)-1e9 - 5, MAXR = (ll)1e9 + 5; struct SegTree { ll merge(ll a, ll b) { return a + b; } const ll neutral = 0; @@ -39,6 +39,7 @@ struct SegTree { else update(rc(p), mid + 1, r, i, x, repl); t[p] = merge(t[lc(p)], t[rc(p)]); } - void sumUpdate(ll i, ll x) { update(0, MINL, MAXR, i, x, 0); } - void assignUpdate(ll i, ll x) { update(0, MINL, MAXR, i, x, 1); } + void update(ll i, ll x, bool repl) { update(0, MINL, MAXR, i, x, repl); } + void sumUpdate(ll i, ll x) { update(i, x, 0); } + void setUpdate(ll i, ll x) { update(i, x, 1); } } seg; diff --git a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Iterativa/itseg_tree.cpp b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Iterativa/itseg_tree.cpp index 5a4f4ebe..6a84ee32 100644 --- a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Iterativa/itseg_tree.cpp +++ b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Iterativa/itseg_tree.cpp @@ -26,9 +26,11 @@ struct SegTree { } return merge(ansl, ansr); } - void update(int i, ll x, bool replace = false) { + void update(int i, ll x, bool replace) { i += n; t[i] = replace ? x : merge(t[i], x); for (i >>= 1; i > 0; i >>= 1) t[i] = merge(t[lc(i)], t[rc(i)]); } + void sumUpdate(int i, ll x) { update(i, x, 0); } + void setUpdate(int i, ll x) { update(i, x, 1); } } seg; diff --git a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy-Esparsa/seg_tree_sparse_lazy.cpp b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy-Esparsa/seg_tree_sparse_lazy.cpp index a27a42bf..af9e25c6 100644 --- a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy-Esparsa/seg_tree_sparse_lazy.cpp +++ b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy-Esparsa/seg_tree_sparse_lazy.cpp @@ -1,4 +1,4 @@ -template +const ll MINL = (ll)-1e9 - 5, MAXR = (ll)1e9 + 5; struct SegTree { ll merge(ll a, ll b) { return a + b; } const ll neutral = 0; @@ -65,6 +65,7 @@ struct SegTree { t[p] = merge(t[lc(p)], t[rc(p)]); } } - void sumUpdate(ll l, ll r, ll val) { update(0, MINL, MAXR, l, r, val, 0); } - void assignUpdate(ll l, ll r, ll val) { update(0, MINL, MAXR, l, r, val, 1); } + void update(ll l, ll r, ll val, bool repl) { update(0, MINL, MAXR, l, r, val, repl); } + void sumUpdate(ll l, ll r, ll val) { update(l, r, val, 0); } + void setUpdate(ll l, ll r, ll val) { update(l, r, val, 1); } } seg; diff --git a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy/seg_tree_lazy.cpp b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy/seg_tree_lazy.cpp index fe131154..d82284e7 100644 --- a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy/seg_tree_lazy.cpp +++ b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Lazy/seg_tree_lazy.cpp @@ -75,6 +75,7 @@ struct SegTree { t[p] = merge(t[lc(p)], t[rc(p)]); } } - void sumUpdate(int l, int r, ll val) { update(1, 0, n - 1, l, r, val, 0); } - void assignUpdate(int l, int r, ll val) { update(1, 0, n - 1, l, r, val, 1); } + void update(int l, int r, ll val, bool repl) { update(1, 0, n - 1, l, r, val, repl); } + void sumUpdate(int l, int r, ll val) { update(l, r, val, 0); } + void setUpdate(int l, int r, ll val) { update(l, r, val, 1); } } seg; diff --git a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Persisente/seg_tree_persistent.cpp b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Persisente/seg_tree_persistent.cpp index aaaca925..ca1f2dcc 100644 --- a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Persisente/seg_tree_persistent.cpp +++ b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree-Persisente/seg_tree_persistent.cpp @@ -29,29 +29,36 @@ struct SegTree { } ll query(ll l, ll r, int root = -1) { if (root == -1) root = roots.back(); + else root = roots[root]; return query(root, MINL, MAXR, l, r); } - void update(int p, int old, ll l, ll r, ll i, ll x) { + void update(int p, int old, ll l, ll r, ll i, ll x, bool repl) { + t[p] = t[old]; if (l == r) { - t[p] = x; // substitui - // t[p] += x; // soma + if (repl) t[p] = x; // substitui + else t[p] += x; // soma return; } ll mid = l + (r - l) / 2; if (i <= mid) { Rc[p] = rc(old); - update(lc(p), lc(old), l, mid, i, x); + update(lc(p), lc(old), l, mid, i, x, repl); } else { Lc[p] = lc(old); - update(rc(p), rc(old), mid + 1, r, i, x); + update(rc(p), rc(old), mid + 1, r, i, x, repl); } t[p] = merge(t[lc(p)], t[rc(p)]); } - int update(ll i, ll x, int root = -1) { + int update(ll i, ll x, bool repl, int root = -1) { + // root é qual versão da segtree vai ser atualizada, + // -1 atualiza a ultima root int new_root = newnode(); if (root == -1) root = roots.back(); - update(new_root, root, MINL, MAXR, i, x); + else root = roots[root]; + update(new_root, root, MINL, MAXR, i, x, repl); roots.push_back(new_root); return roots.back(); } + void sumUpdate(ll i, ll x, int root = -1) { update(i, x, 0, root); } + void setUpdate(ll i, ll x, int root = -1) { update(i, x, 1, root); } } seg; diff --git a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree/seg_tree.cpp b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree/seg_tree.cpp index 9c71dde9..cd3a5091 100644 --- a/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree/seg_tree.cpp +++ b/Codigos/Estruturas-de-Dados/Segment-Tree/Segment-Tree/seg_tree.cpp @@ -47,6 +47,7 @@ struct SegTree { t[p] = merge(t[lc(p)], t[rc(p)]); } } - void sumUpdate(int i, ll x) { update(1, 0, n - 1, i, x, 0); } - void assignUpdate(int i, ll x) { update(1, 0, n - 1, i, x, 1); } + void update(int i, ll x, bool repl) { update(1, 0, n - 1, i, x, repl); } + void sumUpdate(int i, ll x) { update(i, x, 0); } + void setUpdate(int i, ll x) { update(i, x, 1); } } seg; diff --git a/Codigos/Grafos/HLD/HLD-Aresta/README.md b/Codigos/Grafos/HLD/HLD-Aresta/README.md new file mode 100644 index 00000000..fb12fc8b --- /dev/null +++ b/Codigos/Grafos/HLD/HLD-Aresta/README.md @@ -0,0 +1,7 @@ +# [Heavy-Light Decomposition (em Arestas)](hld_edge.cpp) + +Técnica utilizada para decompor uma árvore em cadeias, e assim realizar operações de caminho e subárvore em $\mathcal{O}(\log N \cdot g(N))$, onde $g(N)$ é a complexidade da operação. Esta implementação suporta queries de soma e update de soma/atribuição, pois usa a estrutura de dados `Segment Tree Lazy` desse almanaque, fazendo assim com que updates e consultas sejam $\mathcal{O}(\log^2 N)$. A estrutura (bem como a operação feita nela) pode ser facilmente trocada, basta alterar o código da `Segment Tree Lazy`, ou ainda, utilizar outra estrutura de dados, como uma `Sparse Table`, caso você tenha queries de mínimo/máximo sem updates, por exemplo. Ao mudar a estrutura, pode ser necessário adaptar os métodos `query` e `update` da HLD. + +A HLD pode ser feita com os valores estando tanto nos vértices quanto nas arestas, essa implementação é feita com os valores nas **arestas**, para ter os valores nos vértices, consulte a implementação de HLD em vértices. + +A construção da HLD é feita em $\mathcal{O}(N + b(N))$, onde $b(N)$ é a complexidade de construir a estrutura de dados utilizada. \ No newline at end of file diff --git a/Codigos/Grafos/HLD/HLD-Aresta/hld_edge.cpp b/Codigos/Grafos/HLD/HLD-Aresta/hld_edge.cpp new file mode 100644 index 00000000..717d8447 --- /dev/null +++ b/Codigos/Grafos/HLD/HLD-Aresta/hld_edge.cpp @@ -0,0 +1,79 @@ +const int N = 3e5 + 5; + +vector> adj[N]; + +namespace HLD { + int t, sz[N], pos[N], par[N], head[N]; + SegTree seg; // por padrao, a HLD esta codada para usar a SegTree lazy, + // mas pode usar qualquer estrutura de dados aqui + void dfs_sz(int u, int p = -1) { + sz[u] = 1; + for (int i = 0; i < (int)adj[u].size(); i++) { + auto &[v, w] = adj[u][i]; + if (v != p) { + dfs_sz(v, u); + sz[u] += sz[v]; + if (sz[v] > sz[adj[u][0].first] || adj[u][0].first == p) + swap(adj[u][0], adj[u][i]); + } + } + } + void dfs_hld(int u, int p = -1) { + pos[u] = t++; + for (auto [v, w] : adj[u]) { + if (v != p) { + par[v] = u; + head[v] = (v == adj[u][0].first ? head[u] : v); + dfs_hld(v, u); + } + } + } + void build_hld(int u) { + dfs_sz(u); + t = 0, par[u] = u, head[u] = u; + dfs_hld(u); + } + void build(int n, int root) { + build_hld(root); + vector aux(n, seg.neutral); + for (int u = 0; u < n; u++) { + for (auto [v, w] : adj[u]) + if (u == par[v]) aux[pos[v]] = w; + } + seg.build(aux); + } + ll query(int u, int v) { + if (u == v) return seg.neutral; + if (pos[u] > pos[v]) swap(u, v); + if (head[u] == head[v]) { + return seg.query(pos[u] + 1, pos[v]); + } else { + ll qv = seg.query(pos[head[v]], pos[v]); + ll qu = query(u, par[head[v]]); + return seg.merge(qu, qv); + } + } + ll query_subtree(int u) { + if (sz[u] == 1) return seg.neutral; + return seg.query(pos[u] + 1, pos[u] + sz[u] - 1); + } + // a flag repl diz se o update é de soma ou de replace + void update(int u, int v, ll k, bool repl) { + if (u == v) return; + if (pos[u] > pos[v]) swap(u, v); + if (head[u] == head[v]) { + seg.update(pos[u] + 1, pos[v], k, repl); + } else { + seg.update(pos[head[v]], pos[v], k, repl); + update(u, par[head[v]], k, repl); + } + } + void update_subtree(int u, ll k, bool repl) { + if (sz[u] == 1) return; + seg.update(pos[u] + 1, pos[u] + sz[u] - 1, k, repl); + } + int lca(int u, int v) { + if (pos[u] > pos[v]) swap(u, v); + return head[u] == head[v] ? u : lca(u, par[head[v]]); + } +} diff --git a/Codigos/Grafos/HLD/README.md "b/Codigos/Grafos/HLD/HLD-V\303\251rtice/README.md" similarity index 76% rename from Codigos/Grafos/HLD/README.md rename to "Codigos/Grafos/HLD/HLD-V\303\251rtice/README.md" index c86ee9b2..96924f6c 100644 --- a/Codigos/Grafos/HLD/README.md +++ "b/Codigos/Grafos/HLD/HLD-V\303\251rtice/README.md" @@ -1,7 +1,7 @@ -# [Heavy-Light Decomposition](hld.cpp) +# [Heavy-Light Decomposition (em Vértices)](hld.cpp) Técnica utilizada para decompor uma árvore em cadeias, e assim realizar operações de caminho e subárvore em $\mathcal{O}(\log N \cdot g(N))$, onde $g(N)$ é a complexidade da operação. Esta implementação suporta queries de soma e update de soma/atribuição, pois usa a estrutura de dados `Segment Tree Lazy` desse almanaque, fazendo assim com que updates e consultas sejam $\mathcal{O}(\log^2 N)$. A estrutura (bem como a operação feita nela) pode ser facilmente trocada, basta alterar o código da `Segment Tree Lazy`, ou ainda, utilizar outra estrutura de dados, como uma `Sparse Table`, caso você tenha queries de mínimo/máximo sem updates, por exemplo. Ao mudar a estrutura, pode ser necessário adaptar os métodos `query` e `update` da HLD. -A HLD pode ser feita com os valores estando tanto nos nodos quanto nas arestas, consulte os métodos `build` do código para mais detalhes. +A HLD pode ser feita com os valores estando tanto nos vértices quanto nas arestas, essa implementação é feita com os valores nos **vértices**, para ter os valores nas arestas, consulte a implementação de HLD em arestas. A construção da HLD é feita em $\mathcal{O}(N + b(N))$, onde $b(N)$ é a complexidade de construir a estrutura de dados utilizada. \ No newline at end of file diff --git "a/Codigos/Grafos/HLD/HLD-V\303\251rtice/hld.cpp" "b/Codigos/Grafos/HLD/HLD-V\303\251rtice/hld.cpp" new file mode 100644 index 00000000..81528833 --- /dev/null +++ "b/Codigos/Grafos/HLD/HLD-V\303\251rtice/hld.cpp" @@ -0,0 +1,74 @@ +const int N = 3e5 + 5; + +vector adj[N]; + +namespace HLD { + int t, sz[N], pos[N], par[N], head[N]; + SegTree seg; // por padrao, a HLD esta codada para usar a SegTree lazy, + // mas pode usar qualquer estrutura de dados aqui + void dfs_sz(int u, int p = -1) { + sz[u] = 1; + for (int &v : adj[u]) { + if (v != p) { + dfs_sz(v, u); + sz[u] += sz[v]; + if (sz[v] > sz[adj[u][0]] || adj[u][0] == p) swap(v, adj[u][0]); + } + } + } + void dfs_hld(int u, int p = -1) { + pos[u] = t++; + for (int v : adj[u]) { + if (v != p) { + par[v] = u; + head[v] = (v == adj[u][0] ? head[u] : v); + dfs_hld(v, u); + } + } + } + void build_hld(int u) { + dfs_sz(u); + t = 0, par[u] = u, head[u] = u; + dfs_hld(u); + } + void build(vector v, int root) { // pra buildar com valores nos nodos + build_hld(root); + vector aux(v.size()); + for (int i = 0; i < (int)v.size(); i++) aux[pos[i]] = v[i]; + seg.build(aux); + } + void build(int n, int root) { // pra buildar com neutro nos nodos + build(vector(n, seg.neutral), root); + } + void build(ll *bg, ll *en, int root) { // pra buildar com array de C + build(vector(bg, en), root); + } + ll query(int u, int v) { + if (pos[u] > pos[v]) swap(u, v); + if (head[u] == head[v]) { + return seg.query(pos[u], pos[v]); + } else { + ll qv = seg.query(pos[head[v]], pos[v]); + ll qu = query(u, par[head[v]]); + return seg.merge(qu, qv); + } + } + ll query_subtree(int u) { return seg.query(pos[u], pos[u] + sz[u] - 1); } + // a flag repl diz se o update é de soma ou de replace + void update(int u, int v, ll k, bool repl) { + if (pos[u] > pos[v]) swap(u, v); + if (head[u] == head[v]) { + seg.update(pos[u], pos[v], k, repl); + } else { + seg.update(pos[head[v]], pos[v], k, repl); + update(u, par[head[v]], k, repl); + } + } + void update_subtree(int u, ll k, bool repl) { + seg.update(pos[u], pos[u] + sz[u] - 1, k, repl); + } + int lca(int u, int v) { + if (pos[u] > pos[v]) swap(u, v); + return head[u] == head[v] ? u : lca(u, par[head[v]]); + } +} diff --git a/Codigos/Grafos/HLD/HLD.cpp b/Codigos/Grafos/HLD/HLD.cpp deleted file mode 100644 index 2219bd7f..00000000 --- a/Codigos/Grafos/HLD/HLD.cpp +++ /dev/null @@ -1,100 +0,0 @@ -const int N = 3e5 + 5; - -vector adj[N]; -int sz[N], pos[N], par[N], head[N]; - -namespace HLD { - int t; - bool e = 0; // flag pra dizer se eh de aresta ou nao - SegTree ds; // pode usar qualquer estrutura de dados aqui - - void dfs_sz(int u, int p = -1) { - sz[u] = 1; - for (int &v : adj[u]) { - if (v != p) { - dfs_sz(v, u); - sz[u] += sz[v]; - if (sz[v] > sz[adj[u][0]] || adj[u][0] == p) swap(v, adj[u][0]); - } - } - } - void dfs_hld(int u, int p = -1) { - pos[u] = t++; - for (int v : adj[u]) { - if (v != p) { - par[v] = u; - head[v] = (v == adj[u][0] ? head[u] : v); - dfs_hld(v, u); - } - } - } - void build_hld(int u) { - dfs_sz(u); - t = 0; - par[u] = u; - head[u] = u; - dfs_hld(u); - } - - void build(int root, vector v) { - // usar esse build pra iniciar com valores nos nodos - // (para iniciar vazia, passar o vetor com valores neutros) - build_hld(root); - vector aux(v.size()); - for (int i = 0; i < (int)v.size(); i++) aux[pos[i]] = v[i]; - ds.build(aux); - } - - void build(int root, vector> edges) { - // usar esse build se os valores estiverem nas arestas - for (auto [u, v, w] : edges) { - adj[u].push_back(v); - adj[v].push_back(u); - } - build_hld(root); - e = 1; - assert(edges.size() >= 1); - vector aux(edges.size() - 1); - for (auto [u, v, w] : edges) { - if (pos[u] > pos[v]) swap(u, v); - aux[pos[v]] = w; - } - ds.build(aux); - } - - ll query(int u, int v) { - if (e && u == v) return ds.neutral; - if (pos[u] > pos[v]) swap(u, v); - if (head[u] == head[v]) { - return ds.query(pos[u] + e, pos[v]); - } else { - ll qv = ds.query(pos[head[v]], pos[v]); - ll qu = query(u, par[head[v]]); - return ds.merge(qu, qv); - } - } - ll query_subtree(int u) { - if (e && sz[u] == 1) return ds.neutral; - return ds.query(pos[u] + e, pos[u] + sz[u] - 1); - } - - void update(int u, int v, ll k, bool replace = false) { - if (e && u == v) return; - if (pos[u] > pos[v]) swap(u, v); - if (head[u] == head[v]) { - ds.update(pos[u] + e, pos[v], k, replace); - } else { - ds.update(pos[head[v]], pos[v], k, replace); - update(u, par[head[v]], k, replace); - } - } - void update_subtree(int u, ll k, bool replace = false) { - if (e && sz[u] == 1) return; - ds.update(pos[u] + e, pos[u] + sz[u] - 1, k, replace); - } - - int lca(int u, int v) { - if (pos[u] > pos[v]) swap(u, v); - return head[u] == head[v] ? u : lca(u, par[head[v]]); - } -} \ No newline at end of file