Aula por Arthur Lobo
Nesta aula, abordaremos uma técnica eficiente para contar a quantidade de inversões em um array usando a estrutura de dados Binary Indexed Tree (BIT).
Conhecimento prévio necessário:
O que é uma inversão?
Dado um Array com elementos , dizemos que e estão invertidos (são uma inversão) se e , ou seja, eles estão fora de ordem um em relação ao outro. Formalmente, o par é uma inversão e .
A quantidade de inversões é a quantidade de pares que são uma inversão. Por exemplo, no array existem duas inversões: e .
Comprimindo o Array
Note que a o real valor em cada posição no array não importa, só importa a os valores de cada posição em relação aos outros valores presentes no array. Por exemplo, os arrays e são equivalentes em relação as inversões.
Por conta disso, vamos querer fazer com que os valores no array inicial sejam os menores possíveis, deixando todos eles no intervalo . Os dois arrays citados a cima virariam , em que todos os valores estão de até ().
Para fazer isso, basta utilizarmos a técnica de compreensão de coordenadadas no array inicial. Veja aqui a aula do NOIC sobre compressão de coordenadas: Link da Aula.
Contando as inversões
Vamos contar, para cada , quantos () existem tal que é uma inversão. Nosso objetivo será percorrer o array do final até o começo mantendo uma BIT em que a posição guarda quantos elementos iguais a já foram percorridos, então quando estivermos em , basta contarmos quantos elementos já foram percorridos fazendo uma query na BIT.
Desse jeito, quando estamos em vamos realizar os seguintes passos:
- Sabemos que já percorremos e eles já foram somados na BIT.
- Para contar quantos existem tal que é uma inversão, fazemos uma query na BIT contando quantos elementos menores que já foram somados na BIT e adicionamos isso na resposta: quantidade_de_inversões+= .
- Agora adicionamos na BIT, somando na posição : .
- Agora podemos seguir para , mas com os elementos adicionados na BIT.
Por exemplo, no array , a query retornaria 0 nas posições e , mas retornaria na posição . Já no array , a query retornaria e nas posições e , respectivamente.
Obs: Não esqueça de utilizar long long para contar as inversões!