Segment Trees: Estrutura e Aplicações

Uma Segment Tree é uma estrutura de dados do tipo árvore binária, projetada para particionar intervalos em subintervalos unitários. Cada folha corresponde a um elemento da sequência original, facilitando operações eficientes em intervalos específicos. Essa estrutura permite consultas em O(log N), tornando-a ideal para problemas que envolvem buscas em faixas de dados.

Princípios de Funcionamento

A Segment Tree utiliza divisão binária recursiva para dividir um inetrvalo maior em dois subintervalos menores, construindo uma árvore balanceada. O nó raiz representa o intervalo completo, e as folhas armazenam informações individuais. Essa abordagem suporta operações como:

  • Consultas em intervalos: Obter agregações como soma, máximo ou mínimo dentro de uma faixa especificada.
  • Atualizações em intervalos: Modificar valores em uma faixa inteira, por exemplo, adicionando um valor constante a todos os elementos.
  • Manutenção dinâmica: Atualizar automaticamente as informações quando os dados subjacentes mudam, sem reconstruir a estrutura.

Representação em Memória

Na implementação comum, a Segment Tree é armazenada em um array. O nó raiz ocupa o índice 0. Para um nó no índice i, o filho esquerdo está em 2*i+1 e o filho direito em 2*i+2. Essa representação compacta facilita o acesso e a manipulação eficiente.

Implementação em C++

Inserção de Valores

// Insere um valor na Segment Tree, atualizando contadores ao longo do caminho
void inserir_valor(vector<int>& arvore, int no, int inicio, int fim, int valor) {
    arvore[no]++;
    if (inicio == fim) return;
    int meio = (inicio + fim) / 2;
    int esquerda = no * 2 + 1;
    int direita = no * 2 + 2;
    if (valor <= meio) {
        inserir_valor(arvore, esquerda, inicio, meio, valor);
    } else {
        inserir_valor(arvore, direita, meio + 1, fim, valor);
    }
}</int>

Busca em Inetrvalos

// Retorna o valor associado a um ponto específico na Segment Tree
int buscar_valor(const vector<int>& arvore, int no, int inicio, int fim, int valor) {
    if (inicio == fim) return arvore[no];
    int meio = (inicio + fim) / 2;
    int esquerda = no * 2 + 1;
    int direita = no * 2 + 2;
    if (valor <= meio) {
        return buscar_valor(arvore, esquerda, inicio, meio, valor);
    } else {
        return buscar_valor(arvore, direita, meio + 1, fim, valor);
    }
}</int>

Exibição da Estrutura

// Imprime os nós da Segment Tree em ordem de travessia
void exibir_arvore(const vector<int>& arvore, int no, int inicio, int fim) {
    cout << "[" << inicio << " " << fim << "] nó " << no << " = " << arvore[no] << endl;
    if (inicio == fim) return;
    int meio = (inicio + fim) / 2;
    exibir_arvore(arvore, no * 2 + 1, inicio, meio);
    exibir_arvore(arvore, no * 2 + 2, meio + 1, fim);
}</int>

Tags: segment tree range queries C++ data structure

Publicado em 7-13 07:12