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: