Cod sursa(job #3137715)

Utilizator Uriesu_IuliusUriesu Iulius Uriesu_Iulius Data 14 iunie 2023 17:38:46
Problema Range minimum query Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 1.97 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], lg[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;
}

// O(1)
int query_O1(int a, int b) {
	int d = b - a + 1;
	// fie P cea mai mare putere a lui 2 astfel incat P <= d
	int p = lg[d]; // => P = 2^p
	// d = 6 => P = 4
	// v1 v2 v3 v4 v5 v6
	// intervalul [v1, v4] si [v3, v6]
	return min(rmq[a][p], rmq[b - (1 << p) + 1][p]);
}

int main() {

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

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

	// 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_O1(a, b) << "\n";
	}

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

	return 0;
}