Resolução de Problemas com Decomposição em Blocos: P3203 e P4168

P3203 [HNOI2010] – Bouncing Sheep

Para cada posição, registramos quantos passos são necessários para sair do bloco atual e qual é a posição de destino após a saída. O cálculo é feito de trás para frente dentro de cada bloco.

#include <bits/stdc++.h>
#define MAXN 200100

using namespace std;

int n, m, tam;
int bloco[MAXN], salto[MAXN];
int prox[MAXN], passos[MAXN];
struct Intervalo { int l, r; } inter[MAXN];

int ler() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { s = (s << 1) + (s << 3) + ch - '0'; ch = getchar(); }
    return s * w;
}

void init() {
    tam = sqrt(n);
    for (int i = 0; i < n; i++) bloco[i] = i / tam;
    int ultimoBloco = bloco[n - 1];
    for (int i = 0; i <= ultimoBloco; i++) {
        inter[i].l = i * tam;
        inter[i].r = (i + 1) * tam - 1;
    }
    inter[ultimoBloco].r = n - 1;
}

void recalcula(int l, int r) {
    for (int i = r; i >= l; i--) {
        int destino = i + salto[i];
        if (destino > inter[bloco[i]].r) {
            prox[i] = destino;
            passos[i] = 1;
        } else {
            prox[i] = prox[destino];
            passos[i] = passos[destino] + 1;
        }
    }
}

int main() {
    n = ler();
    for (int i = 0; i < n; i++) salto[i] = ler();
    init();
    recalcula(0, n - 1);
    m = ler();
    for (int i = 0; i < m; i++) {
        int op = ler(), x = ler();
        if (op == 1) {
            int p = x, ans = 0;
            while (p < n) {
                ans += passos[p];
                p = prox[p];
            }
            printf("%d\n", ans);
        } else {
            int y = ler();
            salto[x] = y;
            int b = bloco[x];
            recalcula(inter[b].l, inter[b].r);
        }
    }
    return 0;
}

P4168 [Violet] – Dandelion

Armazenamos a posição de cada cor e pré‑calculamos, para cada par de blocos, o valor que mais se repete (moda) dentro desse intervalo. Consultas: blocos intermediários usam a tabela; bordas são varridas individualmente. É necessário discretizar as cores.

#include <bits/stdc++.h>
#define MAXN 100010

using namespace std;

int n, ids, L, R, total, consultas, ansAnterior, blocoAtual;
int arr[MAXN], nums[MAXN], bucket[MAXN];
int cnt[MAXN], modaBloco[3010][3010], sorted[MAXN];
vector<int> posicoes[MAXN];
map<int, int> compress;

int ler() {
    int s = 0, w = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { s = (s << 1) + (s << 3) + ch - '0'; ch = getchar(); }
    return s * w;
}

int conta(int l, int r, int cor) {
    return upper_bound(posicoes[cor].begin(), posicoes[cor].end(), r)
         - lower_bound(posicoes[cor].begin(), posicoes[cor].end(), l);
}

void precalc(int blocoIni) {
    memset(cnt, 0, sizeof(cnt));
    int melhor = 0, corMelhor = 0;
    int inicio = (blocoIni - 1) * total + 1;
    for (int i = inicio; i <= n; i++) {
        cnt[arr[i]]++;
        if (cnt[arr[i]] > melhor || (cnt[arr[i]] == melhor && arr[i] < corMelhor)) {
            melhor = cnt[arr[i]];
            corMelhor = arr[i];
        }
        modaBloco[blocoIni][bucket[i]] = corMelhor;
    }
}

int consulta(int l, int r) {
    int melhorCnt = 0, corMelhor = 0;
    int blocoL = bucket[l], blocoR = bucket[r];

    if (blocoL + 1 < blocoR) {
        int corMeio = modaBloco[blocoL + 1][blocoR - 1];
        melhorCnt = conta(l, r, corMeio);
        corMelhor = corMeio;
    }

    int limE = min(r, blocoL * total);
    for (int i = l; i <= limE; i++) {
        int c = conta(l, r, arr[i]);
        if (c > melhorCnt || (c == melhorCnt && arr[i] < corMelhor)) {
            melhorCnt = c;
            corMelhor = arr[i];
        }
    }
    if (blocoL != blocoR) {
        int inicioDir = (blocoR - 1) * total + 1;
        for (int i = inicioDir; i <= r; i++) {
            int c = conta(l, r, arr[i]);
            if (c > melhorCnt || (c == melhorCnt && arr[i] < corMelhor)) {
                melhorCnt = c;
                corMelhor = arr[i];
            }
        }
    }
    return nums[corMelhor];
}

int main() {
    n = ler(); consultas = ler();
    for (int i = 1; i <= n; i++) {
        arr[i] = ler();
        sorted[i] = arr[i];
    }
    sort(sorted + 1, sorted + n + 1);
    for (int i = 1; i <= n; i++) {
        if (!compress[sorted[i]]) {
            ids++;
            compress[sorted[i]] = ids;
            nums[ids] = sorted[i];
        }
    }
    for (int i = 1; i <= n; i++) {
        arr[i] = compress[arr[i]];
        posicoes[arr[i]].push_back(i);
    }
    for (int i = 1; i <= ids; i++) posicoes[i].push_back(n + 1);

    total = sqrt(n);
    for (int i = 1; i <= n; i++) bucket[i] = (i - 1) / total + 1;
    int numBlocos = bucket[n];
    for (int i = 1; i <= numBlocos; i++) precalc(i);

    for (int i = 0; i < consultas; i++) {
        L = ler(); R = ler();
        L = (L + ansAnterior - 1) % n + 1;
        R = (R + ansAnterior - 1) % n + 1;
        if (L > R) swap(L, R);
        ansAnterior = consulta(L, R);
        printf("%d\n", ansAnterior);
    }
    return 0;
}

Tags: decomposição em blocos sqrt decomposition HNOI2010 Violet P3203

Publicado em 6-29 04:03