Aula por Lúcio Cardoso
Imagine que é dado um vetor com números inteiros, e precisamos realizar as seguintes operações:
- Somar o valor no elemento de índice do vetor
- Calcular a soma dos valores de índice no intervalo
Nessa aula, será apresentada a esturutura de dados BIT, que consegue realizar as duas operações acima com complexidade .
Descrição da estrutura
Inicialmente, vamos definir o bit menos significativo de um número inteiro . Denote este valor por . é igual ao bit ligado (igual a 1) mais à direita na representação binária de . Por exemplo, como , . No C++, conseguimos encontrar usando a expressão , onde representa o binário.
A BIT (Binary Indexed Tree) é um vetor de mesmo tamanho que . Denotaremos o vetor da BIT por . Esta estrutura é construida tal que, para um índice (), é igual a soma de todos os elementos do vetor no intervalo , Ou seja,
.
Como um exemplo, se , o vetor será igual a .
Função
Esta função adiciona o valor na posição do vetor. Vamos pensar em como utilizar a BIT para realizar esta operação em . Para isso, precisamos pensar em quais índices são tais que será alterado, ou seja, tais que esteja no intervalo .
Perceba que o intervalo de um índice certamente não contém . Logo, o índice é o primeiro índice do vetor que será alterado. Note também que o próximo índice a ser alterado, ou seja, o menor índice maior que alterado, será , já que para qualquer inteiro , o intervalo certamente não contém (verifique!). Assim, o próximo índice que será alterado será , e assim por diante. Dessa forma, chegamos que os índices do vetor que serão somados em serão os seguintes:
, até chegarmos no último número da lista menor ou igual a .
Perceba que a lista acima possui no máximo índices, pois as potências de somadas em cada valor (por exemplo, ) são todas distintas (já que a lista possui valores estritamente crescentes), e há no máximo potências de distintas menores ou iguais a . Portanto, a complexidade da função é . Segue o código abaixo para melhor entendimento:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const int MAXN = 10010; | |
int bit[MAXN], n; | |
// soma v em V[x] | |
void upd(int x, int v) | |
{ | |
// lsb(x) = x&-x | |
for (; x <= n; x += (x&-x)) | |
bit[x] += v; | |
} |
Função
A função calcula, utilizando a BIT, a soma de todos os números em de a . Note, assim, que a soma dos valores no intervalo será .
Inicialmente, possuímos a soma dos valores no intervalo , já calculada, pois esta soma é igual a . Além disso, também possuímos a soma do intervalo , que é exatamente .
Seguindo este processo, eventualmente vamos conseguir particionar o intervalo em intervalos menores e disjuntos, e assim, obter a sua soma. Portanto, vamos realizar o seguinte algoritmo:
- Somar em nossa variável de resposta
- Subtrair de
- Repetir a etapa enquanto .
Pelo mesmo argumento usado na função , é possível perceber que o algoritmo acima realizará no máximo operações. Confira o código para melhor entendimento:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const int MAXN = 10010; | |
int bit[MAXN], n; | |
// soma de [1, x] | |
int soma(int x) | |
{ | |
int ans = 0; | |
for (; x > 0; x -= (x&-x)) | |
ans += bit[x]; | |
return ans; | |
} |
Problemas para praticar
A estrutura de dados BIT pode ser usada para resolver diversos problemas. Pense nos problemas na lista abaixo: