Skip to content

Commit

Permalink
consertei hld, separei hld em dois arquivos (vértice e aresta), melho…
Browse files Browse the repository at this point in the history
…rei os updates das segs (#171)

* consertei hld, separei em dois arquivos, melhorei os updates das segs

* minor fixes

* minor fix comentario
  • Loading branch information
joaomarcosth9 authored Sep 11, 2024
1 parent 1ec8361 commit 6399c63
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 120 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
template <ll MINL = (ll)-1e9 - 5, ll MAXR = (ll)1e9 + 5>
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;
Expand Down Expand Up @@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
template <ll MINL = (ll)-1e9 - 5, ll MAXR = (ll)1e9 + 5>
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;
Expand Down Expand Up @@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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;
7 changes: 7 additions & 0 deletions Codigos/Grafos/HLD/HLD-Aresta/README.md
Original file line number Diff line number Diff line change
@@ -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.
79 changes: 79 additions & 0 deletions Codigos/Grafos/HLD/HLD-Aresta/hld_edge.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const int N = 3e5 + 5;

vector<pair<int, ll>> 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<ll> 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]]);
}
}
Original file line number Diff line number Diff line change
@@ -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.
74 changes: 74 additions & 0 deletions Codigos/Grafos/HLD/HLD-Vértice/hld.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
const int N = 3e5 + 5;

vector<int> 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<ll> v, int root) { // pra buildar com valores nos nodos
build_hld(root);
vector<ll> 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<ll>(n, seg.neutral), root);
}
void build(ll *bg, ll *en, int root) { // pra buildar com array de C
build(vector<ll>(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]]);
}
}
100 changes: 0 additions & 100 deletions Codigos/Grafos/HLD/HLD.cpp

This file was deleted.

0 comments on commit 6399c63

Please sign in to comment.