Cod sursa(job #3137713)

Utilizator Uriesu_IuliusUriesu Iulius Uriesu_Iulius Data 14 iunie 2023 17:31:24
Problema Range minimum query Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 1.62 kb
// Range Minimum Query

/*
n secvente de lungime 1
n-1 secvente de lungime 2
n-3 secvente de lungime 4
n-7 secvente de lungime 8
...
				lungime n

=> spatiu de stocare O(n * log n)
retinem MINIMUL din intervalele:
[1, 1], [2, 2], [3, 3], ... , [n, n]
[1, 2], [2, 3], [3, 4], ... , [n-1, n]
[1, 4], [2, 5], [3, 6], ... , [n-3, n]
...
[1, k], [2, k+1], ... , [n-k+1, n]
k - putere a lui 2

2^k -> (1 << k)

rmq[n][log n]
rmq[i][j] - minimul intervalului care incepe pe pozitia i si are lungime 2^j
*/

#include <iostream>
#include <fstream>

using namespace std;

const int mxN = 1e5 + 5, lgN = 17;
int n, m, v[mxN];
int rmq[mxN][lgN];

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

// O(log n)
int query(int a, int b) {
	// min [a, b] ?
	int d = b - a + 1, mini = v[a];
	int p = 0;
	while (d) {
		if (d % 2 == 1) {
			mini = min(mini, rmq[a][p]);
			a += (1 << p);
		}
		p++;
		d /= 2;
	}
	return mini;
}

int query_O1(int a, int b) {

}

int main() {

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

	// i => i + (1 << j) - 1

	// O(n * log n)
	for (int j = 1; j < lgN; j++) {
		for (int i = 1; i + (1 << j) - 1 <= n; i++) {
			// interval care incepe la i de lungime 2^(j-1)
			// interval care incepe la i + 2^(j-1) de lungime 2^(j-1)
			// => interval care incepe la i de lungime 2^j
			rmq[i][j] = min(rmq[i][j - 1], rmq[i + (1 << (j - 1))][j - 1]);
		}
	}

	// O(m * log n)
	for (int i = 1; i <= m; i++) {
		int a, b;
		fin >> a >> b;
		fout << query(a, b) << "\n";
	}

	// Total: O(n * log n + m * log n)

	return 0;
}