Cod sursa(job #789972)

Utilizator vendettaSalajan Razvan vendetta Data 19 septembrie 2012 22:50:09
Problema Range minimum query Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.29 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <set>
#include <queue>
#include <deque>

using namespace std;

ifstream f("rmq.in");
ofstream g("rmq.out");

#define nmax 100005
#define inf (1<<29)
#define ll long long

int n, m, a[nmax], Min[17][nmax], Exp[nmax];

void citeste(){

	f >> n >> m;
	for(int i=1; i<=n; ++i) f >> a[i];

}

void preprocesare(){

    //initializez
    //am intervalul i,i+2^0-1;
    for(int i=1; i<=n; ++i) Min[0][i] = a[i];

    for(int i=1; i<=17; ++i){
        //nu are rost sa ma duc pana la n; trebuie respectata conditia j + 2^i - 1 <= n => ca j <= (n- 2^i +1)
        for(int j=1; j<=n-(1<<i)+1; ++j){
            int unde = j + (1<<i)-1;//intervalul ocupat de pozitia j; adica intervalul [j, j+(1<<i)-1];
            int tata = unde - (1<<(i-1)) + 1;//
            //deci eu dublez intervalul curent(adaugand o putere a lui doi);
            //pot ramane la minimul de pana acum sau sa iau minimul de pe intervalul [j + (1<<(i-1))-1, j+(1<<i)-1]
            Min[i][j] = min(Min[i-1][j], Min[i-1][tata]);
        }
    }

}

void rezolva(){

    //minimul de pe intervalul [x,y]; imi preprocesez o matrice Min[i][j] = minimul de pe intervalul [j, j+(2^i)-1]
    //+imi preprocesez un vector Exp[poz] = k; cel mai mare k a. i. 2^k <= poz;

    preprocesare();

    Exp[1] = 0;
    for(int i=2; i<=n; ++i){
        Exp[i] = Exp[i/2] + 1;
    }

    for(int i=1; i<=m; ++i){
        int x,y;
        f >> x >> y;
        //ideea e sa impart acest interval in 2 intervale de puteri ale lui 2 (pt complexitataea o(1) )
        //aflu cel mai mare k a. i. x + 2^k-1 <= y;
        //aflu lungimea intervalului si acum trebuie sa caut un maxim k a. i. 2^k <= lungime
        int lung = y-x+1;
        int k = Exp[lung];//cel mai mare k a. i. 2^k <= lung;

        //aflu minimul de pe intervalul [x, x+(2^k)-1]
        int rez = inf;
        rez = min(rez, Min[k][x]);

        //aflu minimul de pe intervalul; Fie Y = x + ceva; acum trebuie sa gasesc acel ceva a. i. Y + (2^k) - 1 == y;
        //=> ceva = y - (2^k) + 1;
        int new_X = y - (1<<k)+1;
        rez = min(rez, Min[k][new_X]);
        g << rez << "\n";
    }

}

int main(){

    citeste();
    rezolva();

    f.close();
    g.close();

    return 0;

}