Cod sursa(job #3279305)

Utilizator jumaracosminJumara Cosmin-Mihai jumaracosmin Data 22 februarie 2025 14:28:31
Problema Range minimum query Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 2.13 kb
#include <bits/stdc++.h>

#pragma GCC optimize("O2")

std::ifstream fin("rmq.in");
std::ofstream fout("rmq.out");

/*
    Pentru fiecare poziție i din v, vom calcula mai multe minime. Pentru fiecare
    secvență de lungime putere de 2 care începe la poziția i, vom calcula minimul dintre
    elementele ei. Deci, pentru fiecare poziție din v vom avea maximum log2 n minime de calculat (atâtea
    puteri de 2 sunt mai mici sau egale cu n).
    
    Astfel, vom obține o matrice r[p][i] = minimul din v pentru elementele dintr-o secvență
    de lungime 2^p care începe la poziția i.
*/

const int size = 1e5 + 5;
const int p_max = 20;

int n, q, st, dr;
int a[size], E[size];
int rmq[p_max][size];

int main() 
{
    std::ios_base::sync_with_stdio(false);
    fin.tie(nullptr);
    fout.tie(nullptr);

    // Obs: rmq[0][i] = min(i, i + 2^0 - 1) = min(i, i) = a[i]

    fin >> n >> q;
    for(int i = 1; i <= n; ++i)
    {
        fin >> a[i];
        rmq[0][i] = a[i];
    }


    // Obs: rmq[p] depinde doar de rmq[p - 1], deci calculam liniile in ordine crescatoare
    // Obs: rmq[p][i] = min(rmq[p - 1][i], rmq[p - 1][i + 2 ^ (p - 1)] (se observa usor)

    for(int p = 1; (1 << p) <= n; ++p)
        for(int i = 1; i <= n; ++i)
        {
            rmq[p][i] = rmq[p - 1][i];
            int j = i + (1 << (p - 1));
            if(j <= n)
                rmq[p][i] = std::min(rmq[p][i], rmq[p - 1][j]);
        }
    
    // Obs: Pentru a raspunde la queries avem nevoie de o impartire a bucatii [st, dr] in 2 bucati de lungime
    // egala cu o putere de 2. Fie 2^e = puterea de 2 maxima <= L (unde L este dr - st + 1, lungimea sirului)
    // In acest fel putem descompune Q(st, dr) in min(rmq[e][st], rmq[e][dr - 2^e + 1])
    // Tot ce ne mai trebuie este acel "e", cum il aflam? Cu ajutorul unei precalculari!
    
    E[1] = 0;
    for(int i = 2; i <= n; ++i)
        E[i] = 1 + E[i / 2];

    while(q--)
    {
        fin >> st >> dr;
        int e = E[dr - st + 1];
        int ans = std::min(rmq[e][st], rmq[e][dr - (1 << e) + 1]);
        fout << ans << "\n";
    }

    return 0;
}