Skip to content

Commit

Permalink
Merge pull request #72 from BRUTEUdesc/joao
Browse files Browse the repository at this point in the history
Joao
  • Loading branch information
joaomarcosth9 authored Feb 19, 2024
2 parents 9bcf316 + c0eb51d commit c91d992
Show file tree
Hide file tree
Showing 16 changed files with 123 additions and 108 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# [DSU Bipartido](bipartite_dsu.cpp)

DSU que mantém se um conjunto é bipartido (visualize os conjuntos como componentes conexas de um grafo e os elementos como vértices). O método $unite$ adiciona uma aresta entre os dois elementos dados, e retorna $true$ se os elementos estavam em conjuntos diferentes (componentes conexas diferentes) e $false$ caso contrário. O método $bipartite$ retorna $true$ se o conjunto (componente conexa) que contém o elemento dado é bipartido e $false$ caso contrário. Todas as operações são $\mathcal{O}(\log n)$.
DSU que mantém se um conjunto é bipartido (visualize os conjuntos como componentes conexas de um grafo e os elementos como vértices). O método $unite$ adiciona uma aresta entre os dois elementos dados, e retorna `true` se os elementos estavam em conjuntos diferentes (componentes conexas diferentes) e `false` caso contrário. O método `bipartite` retorna `true` se o conjunto (componente conexa) que contém o elemento dado é bipartido e `false` caso contrário. Todas as operações são $\mathcal{O}(\log n)$.
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,31 @@ struct Full_DSU {
int color(int a) { return a == par[a] ? c[a] : c[a] ^ color(par[a]); }
bool bipartite(int a) { return bip[find(a)]; }
void checkpoint() { changes.emplace(); }
void save(int &a) { changes.top().emplace(a, a); }
void change(int &a, int b) {
changes.top().emplace(a, a);
a = b;
}
bool unite(int a, int b) {
bool equal_color = color(a) == color(b);
a = find(a), b = find(b);
if (a == b) {
if (equal_color) {
save(bip[a]);
save(all_bipartite);
bip[a] = 0;
all_bipartite = 0;
change(bip[a], 0);
change(all_bipartite, 0);
}
return false;
}
if (sz[a] < sz[b]) {
swap(a, b);
}
save(number_of_sets);
save(par[b]);
save(sz[a]);
save(c[b]);
save(bip[a]);
save(all_bipartite);
number_of_sets--;
par[b] = a;
sz[a] += sz[b];
change(number_of_sets, number_of_sets - 1);
change(par[b], a);
change(sz[a], sz[a] + sz[b]);
change(bip[a], bip[a] && bip[b]);
change(all_bipartite, all_bipartite && bip[a]);
if (equal_color) {
c[b] = 1;
change(c[b], 1);
}
bip[a] &= bip[b];
all_bipartite &= bip[a];
return true;
}
void rollback() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# [DSU com Rollback](rollback_dsu.cpp)

DSU que desfaz as últimas operações. O método $checkpoint$ salva o estado atual da estrutura, e o método $rollback$ desfaz as últimas operações até o último checkpoint. As operações de unir dois conjuntos e verificar em qual conjunto um elemento está são $\mathcal{O}(\log n)$, o rollback é $\mathcal{O}(k)$, onde $k$ é o número de alterações a serem desfeitas e o $checkpoint$ é $\mathcal{O}(1)$. Importante notar que o rollback não altera a complexidade de uma solução, uma vez que $\sum k = \mathcal{O}(q)$, onde $q$ é o número de operações realizadas.
DSU que desfaz as últimas operações. O método `checkpoint` salva o estado atual da estrutura, e o método `rollback` desfaz as últimas operações até o último checkpoint. As operações de unir dois conjuntos e verificar em qual conjunto um elemento está são $\mathcal{O}(\log n)$, o rollback é $\mathcal{O}(k)$, onde $k$ é o número de alterações a serem desfeitas e o `checkpoint` é $\mathcal{O}(1)$. Importante notar que o rollback não altera a complexidade de uma solução, uma vez que $\sum k = \mathcal{O}(q)$, onde $q$ é o número de operações realizadas.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ struct Rollback_DSU {
}
int find(int a) { return a == par[a] ? a : find(par[a]); }
void checkpoint() { changes.emplace(); }
void save(int &a) { changes.top().emplace(a, a); }
void change(int &a, int b) {
changes.top().emplace(a, a);
a = b;
}
bool unite(int a, int b) {
a = find(a), b = find(b);
if (a == b) {
Expand All @@ -17,12 +20,9 @@ struct Rollback_DSU {
if (sz[a] < sz[b]) {
swap(a, b);
}
save(number_of_sets);
save(par[b]);
save(sz[a]);
number_of_sets--;
par[b] = a;
sz[a] += sz[b];
change(number_of_sets, number_of_sets - 1);
change(par[b], a);
change(sz[a], sz[a] + sz[b]);
return true;
}
void rollback() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# [DSU](dsu.cpp)

Estrutura que mantém uma coleção de conjuntos e permite as operações de unir dois conjuntos e verificar em qual conjunto um elemento está, ambas em $\mathcal{O}(1)$ amortizado. O método $find$ retorna o representante do conjunto que contém o elemento, e o método $unite$ une os conjuntos que contém os elementos dados, retornando $true$ se eles estavam em conjuntos diferentes e $false$ caso contrário.
Estrutura que mantém uma coleção de conjuntos e permite as operações de unir dois conjuntos e verificar em qual conjunto um elemento está, ambas em $\mathcal{O}(1)$ amortizado. O método `find` retorna o representante do conjunto que contém o elemento, e o método `unite` une os conjuntos que contém os elementos dados, retornando `true` se eles estavam em conjuntos diferentes e `false` caso contrário.
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# [DSU Offline](offline_dsu.cpp)

Algoritmo que utiliza o Full DSU (DSU com Rollback e Bipartido) que permite adição e **remoção** de arestas. O algoritmo funciona de maneira offline, recebendo previamente todas as operações de adição e remoção de arestas, bem como todas as perguntas (de qualquer tipo, conectividade, bipartição, etc), e retornando as respostas para cada pergunta no retorno do método $solve$. Complexidade total $\mathcal{O}(q\cdot(\log q + \log n))$, onde $q$ é o número de operações realizadas e $n$ é o número de nodos.
Algoritmo que utiliza o Full DSU (DSU com Rollback e Bipartido) que permite adição e **remoção** de arestas. O algoritmo funciona de maneira offline, recebendo previamente todas as operações de adição e remoção de arestas, bem como todas as perguntas (de qualquer tipo, conectividade, bipartição, etc), e retornando as respostas para cada pergunta no retorno do método `solve`. Complexidade total $\mathcal{O}(q\cdot(\log q + \log n))$, onde $q$ é o número de operações realizadas e $n$ é o número de nodos.
2 changes: 1 addition & 1 deletion Codigos/Estruturas-de-Dados/Fenwick-Tree/Fenwick/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# [Fenwick Tree](fenwick_tree.cpp)

Árvore de Fenwick (ou BIT) é uma estrutura de dados que permite atualizações pontuais e consultas de prefixos em um vetor em $\mathcal{O}(\log n)$. A implementação abaixo é 0-indexada (é mais comum encontrar a implementação 1-indexada). A consulta em ranges arbitrários com o método $query$ é possível para qualquer operação inversível, como soma, XOR, multiplicação, etc. A implementação abaixo é para soma, mas é fácil adaptar para outras operações. O método $update$ soma $d$ à posição $i$ do vetor, enquanto o método $updateSet$ substitue o valor da posição $i$ do vetor por $d$.
Árvore de Fenwick (ou BIT) é uma estrutura de dados que permite atualizações pontuais e consultas de prefixos em um vetor em $\mathcal{O}(\log n)$. A implementação abaixo é 0-indexada (é mais comum encontrar a implementação 1-indexada). A consulta em ranges arbitrários com o método `query` é possível para qualquer operação inversível, como soma, XOR, multiplicação, etc. A implementação abaixo é para soma, mas é fácil adaptar para outras operações. O método `update` soma $d$ à posição $i$ do vetor, enquanto o método `updateSet` substitue o valor da posição $i$ do vetor por $d$.
2 changes: 1 addition & 1 deletion Codigos/Estruturas-de-Dados/Interval-Tree/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@

Estrutura que trata intersecções de intervalos.

Capaz de retornar todos os intervalos que intersectam $[L, R]$. Contém métodos $insert({L, R, ID})$, $erase({L, R, ID})$, $overlaps(L, R)$ e $find({L, R, ID})$. É necessário inserir e apagar indicando tanto os limites quanto o ID do intervalo. Todas as operações são $\mathcal{O}(\log n)$, exceto $overlaps$ que é $\mathcal{O}(k + \log n)$, onde $k$ é o número de intervalos que intersectam $[L, R]$. Também podem ser usadas as operações padrões de um `std::set`
Capaz de retornar todos os intervalos que intersectam $[L, R]$. Contém métodos `insert({L, R, ID})`, `erase({L, R, ID})`, `overlaps(L, R)` e `find({L, R, ID})`. É necessário inserir e apagar indicando tanto os limites quanto o ID do intervalo. Todas as operações são $\mathcal{O}(\log n)$, exceto `overlaps` que é $\mathcal{O}(k + \log n)$, onde $k$ é o número de intervalos que intersectam $[L, R]$. Também podem ser usadas as operações padrões de um `std::set`
8 changes: 2 additions & 6 deletions Codigos/Estruturas-de-Dados/LiChao-Tree/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@

Uma árvore de funções. Retorna o $f(x)$ máximo em um ponto $x$.

Para retornar o minimo deve-se inserir o negativo da função e pegar o negativo do resultado. Ou, alterar a função de comparação da árvore se souber mexer.
Para retornar o minimo deve-se inserir o negativo da função ($g(x) = -ax - b$) e pegar o negativo do resultado. Ou, alterar a função de comparação da árvore se souber mexer.

Funciona para funções com a seguinte propriedade, sejam duas funções $f(x)$ e $g(x)$, uma vez que $f(x)$ passa a ganhar/perder pra $g(x)$, $f(x)$ nunca mais passa a perder/ganhar pra $g(x)$. Em outras palavras, $f(x)$ e $g(x)$ se intersectam no máximo uma vez.

Essa implementação está pronta para usar função linear do tipo $f(x) = ax + b$.

Sendo $L$ o tamanho do intervalo:

- Complexidade de consulta: $\mathcal{O}(log(L))$

- Complexidade de update: $\mathcal{O}(log(L))$
Sendo $L$ o tamanho do intervalo, a complexidade de consulta e inserção de funções é $\mathcal{O}(log(L))$.
98 changes: 56 additions & 42 deletions Codigos/Estruturas-de-Dados/LiChao-Tree/lichao_tree.cpp
Original file line number Diff line number Diff line change
@@ -1,51 +1,65 @@
typedef long long ll;
template <ll MINL = ll(-1e9 - 5), ll MAXR = ll(1e9 + 5)> struct LichaoTree {
const ll INF = ll(2e18) + 10;
struct Line {
ll a, b;
Line(ll a_ = 0, ll b_ = -INF) : a(a_), b(b_) { }
ll operator()(ll x) { return a * x + b; }
};
vector<Line> tree;
vector<int> L, R;

const ll MAXN = 2e5 + 5, INF = 1e18 + 9, MAXR = 1e18;
int newnode() {
tree.push_back(Line());
L.push_back(-1);
R.push_back(-1);
return int(tree.size() - 1);
}

struct Line {
ll a, b = -INF;
__int128 operator()(ll x) { return (__int128)a * x + b; }
} tree[4 * MAXN];
int idx = 0, L[4 * MAXN], R[4 * MAXN];
LichaoTree() { newnode(); }

int le(int n) {
if (!L[n]) {
L[n] = ++idx;
}
return L[n];
}
int ri(int n) {
if (!R[n]) {
R[n] = ++idx;
int le(int u) {
if (L[u] == -1) {
L[u] = newnode();
}
return L[u];
}
return R[n];
}

void insert(Line line, int n = 0, ll l = -MAXR, ll r = MAXR) {
ll mid = (l + r) / 2;
bool bl = line(l) < tree[n](l);
bool bm = line(mid) < tree[n](mid);
if (!bm) {
swap(tree[n], line);
}
if (l == r) {
return;
int ri(int u) {
if (R[u] == -1) {
R[u] = newnode();
}
return R[u];
}
if (bl != bm) {
insert(line, le(n), l, mid);
} else {
insert(line, ri(n), mid + 1, r);
}
}

__int128 query(int x, int n = 0, ll l = -MAXR, ll r = MAXR) {
if (l == r) {
return tree[n](x);
void insert(Line line, int n = 0, ll l = MINL, ll r = MAXR) {
ll mid = (l + r) / 2;
bool bl = line(l) > tree[n](l);
bool bm = line(mid) > tree[n](mid);
bool br = line(r) > tree[n](r);
if (bm) {
swap(tree[n], line);
}
if (line.b == -INF) {
return;
}
if (bl != bm) {
insert(line, le(n), l, mid - 1);
} else if (br != bm) {
insert(line, ri(n), mid + 1, r);
}
}
ll mid = (l + r) / 2;
if (x < mid) {
return max(tree[n](x), query(x, le(n), l, mid));
} else {
return max(tree[n](x), query(x, ri(n), mid + 1, r));

ll query(int x, int n = 0, ll l = MINL, ll r = MAXR) {
if (tree[n](x) == -INF || (l > r))
return -INF;
if (l == r) {
return tree[n](x);
}
ll mid = (l + r) / 2;
if (x < mid) {
return max(tree[n](x), query(x, le(n), l, mid - 1));
} else {
return max(tree[n](x), query(x, ri(n), mid + 1, r));
}
}
}
};
9 changes: 2 additions & 7 deletions Codigos/Matemática/Sum-of-floor-(n-div-i)/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# [Soma do floor (n/i)](sum_of_floor.cpp)

<!-- DESCRIPTION -->
Computa
Esse código computa, em $\mathcal{O}(\sqrt{n})$, o seguinte somatório:

$$ \sum_{i=1}^{n} \lfloor\frac{n}{i}\rfloor $$

<!-- DESCRIPTION -->

- Complexidade de tempo: $\mathcal{O}(\sqrt{n})$
$$ \sum_{i=1}^{n} \left\lfloor \frac{n}{i}\right\rfloor $$
32 changes: 17 additions & 15 deletions Codigos/Primitivas/Modular-Int/mint.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
template <int mod> struct Mint {
using m = Mint;
int val;
Mint() : val(0) { }
int v;
Mint() : v(0) { }
Mint(ll v) {
if (v < -mod || v >= 2 * mod) {
if (v < -mod or v >= 2 * mod) {
v %= mod;
}
if (v >= mod) {
Expand All @@ -12,33 +12,35 @@ template <int mod> struct Mint {
if (v < 0) {
v += mod;
}
val = int(v);
v = int(v);
}
bool operator==(const m &o) const { return v == o.v; }
bool operator!=(const m &o) const { return v != o.v; }
bool operator<(const m &o) const { return v < o.v; }
m pwr(m b, ll e) {
m res = 1;
while (e) {
if (e & 1)
while (e > 0) {
if (e & 1) {
res *= b;
}
b *= b, e >>= 1;
}
return res;
}
m &operator+=(const m &o) {
val += o.val;
if (val >= mod) {
val -= mod;
if ((v += o.v) >= mod) {
v -= mod;
}
return *this;
}
m &operator-=(const m &o) {
val -= o.val;
if (val < 0) {
val += mod;
if ((v -= o.v) < 0) {
v += mod;
}
return *this;
}
m &operator*=(const m &o) {
val = int((ll)val * o.val % mod);
v = int(ll(v) * o.v % mod);
return *this;
}
m &operator/=(const m &o) { return *this *= pwr(o, mod - 2); }
Expand All @@ -51,7 +53,7 @@ template <int mod> struct Mint {
friend m operator*(m a, const m &b) { return a *= b; }
friend m operator/(m a, const m &b) { return a /= b; }
friend m operator^(m a, ll e) { return a ^= e; }
friend ostream &operator<<(ostream &os, const m &a) { return os << a.val; }
friend ostream &operator<<(ostream &os, const m &a) { return os << a.v; }
friend istream &operator>>(istream &is, m &a) {
ll x;
is >> x, a = m(x);
Expand All @@ -60,4 +62,4 @@ template <int mod> struct Mint {
};

const int mod = 998244353;
using mint = Mint<mod>;
using mint = Mint<mod>;
13 changes: 13 additions & 0 deletions LaTeX/STL.tex
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
\chapter{STL (Standard Template Library - C++)}

Os templates da STL são estruturas de dados e algoritmos já implementadas em \texttt{C++} que facilitam as implementações, além de serem muito eficients.
Em geral, todas estão incluídas no cabeçalho \texttt{<bits/stdc++.h>}. As estruturas são templates genéricos, podem ser usadas com qualquer tipo, todos os exemplos a seguir são com \texttt{int} apenas por motivos de simplicidade.

\section{Vector}

Um vetor dinâmico (que pode crescer e diminuir de tamanho).
Expand Down Expand Up @@ -48,6 +51,14 @@ \section{Set}
\item \texttt{s.end()}: Retorna um iterador para o elemento seguinte ao último do conjunto - $\mathcal{O}(1)$
\end{itemize}

\section{Multiset}

Basicamente um \texttt{set}, mas permite elementos repetidos. Possui todos os métodos de um \texttt{set}.

Declaração: \texttt{multiset<int> ms}.

Um detalhe é que, ao usar o método \texttt{erase}, ele remove todas as ocorrências do elemento. Para remover apenas uma ocorrência, usar \texttt{ms.erase(ms.find(x))}.

\section{Map}

Um conjunto de pares chave-valor, onde as chaves são únicas. Por baixo, é uma árvore de busca binária balanceada.
Expand Down Expand Up @@ -91,6 +102,8 @@ \section{Priority Queue}
\item \texttt{pq.empty()}: Retorna \texttt{true} se a fila de prioridade estiver vazia - $\mathcal{O}(1)$
\end{itemize}

Para fazer uma fila de prioridade que o menor elemento é o primeiro a sair, usar \texttt{priority\_queue<int, vector<int>, greater<>> pq}.

\section{Stack}

Uma pilha (último a entrar, primeiro a sair).
Expand Down
Loading

0 comments on commit c91d992

Please sign in to comment.