FHQ-Treap e Splay: Implementação e Operações

Conceitos Fundamentais do FHQ-Treap

O FHQ-Treap opera através das operações de divisão e mesclagem, permitindo manutanção de sequências e persistência. Armazena dados como filhos esquerdo (esq) e direito (dir), valor (chave), tamanho da subárvore (tam) e valor aleatório (prior) para balanceamento.

Autalização de Tamanho

void atualizar_tamanho(int no) {
    arvore[no].tam = arvore[arvore[no].esq].tam + arvore[arvore[no].dir].tam + 1;
}

Criação de Nó

int novo_no(int valor) {
    arvore[++contador] = {0, 0, valor, rand(), 1};
    return contador;
}

Divisão por Valor

void dividir_valor(int no, int valor_ref, int &esq, int &dir) {
    if (!no) { esq = dir = 0; return; }
    if (arvore[no].chave <= valor_ref) {
        esq = no;
        dividir_valor(arvore[no].dir, valor_ref, arvore[no].dir, dir);
    } else {
        dir = no;
        dividir_valor(arvore[no].esq, valor_ref, esq, arvore[no].esq);
    }
    atualizar_tamanho(no);
}

Divisão por Tamanho

void dividir_tamanho(int no, int tam_ref, int &esq, int &dir) {
    if (!no) { esq = dir = 0; return; }
    int tam_esq = arvore[arvore[no].esq].tam;
    if (tam_esq < tam_ref) {
        esq = no;
        dividir_tamanho(arvore[no].dir, tam_ref - tam_esq - 1, arvore[no].dir, dir);
    } else {
        dir = no;
        dividir_tamanho(arvore[no].esq, tam_ref, esq, arvore[no].esq);
    }
    atualizar_tamanho(no);
}

Mesclagem

int mesclar(int esq, int dir) {
    if (!esq || !dir) return esq | dir;
    if (arvore[esq].prior < arvore[dir].prior) {
        arvore[esq].dir = mesclar(arvore[esq].dir, dir);
        atualizar_tamanho(esq);
        return esq;
    } else {
        arvore[dir].esq = mesclar(esq, arvore[dir].esq);
        atualizar_tamanho(dir);
        return dir;
    }
}

Inserção

void inserir(int valor) {
    int esq, dir;
    dividir_valor(raiz, valor, esq, dir);
    raiz = mesclar(mesclar(esq, novo_no(valor)), dir);
}

Remoção

void remover(int valor) {
    int esq, meio, dir;
    dividir_valor(raiz, valor, esq, dir);
    dividir_valor(esq, valor - 1, esq, meio);
    meio = mesclar(arvore[meio].esq, arvore[meio].dir);
    raiz = mesclar(mesclar(esq, meio), dir);
}

Cnosulta de Posição

int consultar_posicao(int valor) {
    int esq, dir;
    dividir_valor(raiz, valor - 1, esq, dir);
    int posicao = arvore[esq].tam + 1;
    raiz = mesclar(esq, dir);
    return posicao;
}

Consulta por Posição

int consultar_valor(int no, int pos) {
    int tam_esq = arvore[arvore[no].esq].tam;
    if (pos <= tam_esq) return consultar_valor(arvore[no].esq, pos);
    if (pos == tam_esq + 1) return arvore[no].chave;
    return consultar_valor(arvore[no].dir, pos - tam_esq - 1);
}

Antecessor

int antecessor(int valor) {
    int esq, dir;
    dividir_valor(raiz, valor - 1, esq, dir);
    int resultado = consultar_valor(esq, arvore[esq].tam);
    raiz = mesclar(esq, dir);
    return resultado;
}

Sucessor

int sucessor(int valor) {
    int esq, dir;
    dividir_valor(raiz, valor, esq, dir);
    int resultado = consultar_valor(dir, 1);
    raiz = mesclar(esq, dir);
    return resultado;
}

Inversão de Intervalo

Para inversão de intervalos, utiliza-se divisão por tamanho e marcação de inversão:

void inverter_filhos(int no) {
    if (!no) return;
    std::swap(arvore[no].esq, arvore[no].dir);
    arvore[arvore[no].esq].marca ^= 1;
    arvore[arvore[no].dir].marca ^= 1;
    arvore[no].marca = 0;
}

void inverter_intervalo(int inicio, int fim) {
    int esq, meio, dir;
    dividir_tamanho(raiz, fim, esq, dir);
    dividir_tamanho(esq, inicio - 1, esq, meio);
    arvore[meio].marca ^= 1;
    raiz = mesclar(mesclar(esq, meio), dir);
}

Tags: FHQ-Treap splay Treap Divisão-e-Mesclagem Inversão-de-Intervalo

Publicado em 7-14 22:54