Cod sursa(job #2751279)

Utilizator vali_27Bojici Valentin vali_27 Data 14 mai 2021 18:11:08
Problema Range minimum query Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 1.73 kb
#include <iostream>
#include <fstream>
#include <cmath>
 
std::ifstream f("rmq.in");
std::ofstream g("rmq.out");

int logaritm[100001],n,m;

// sparse table -> tbl[i][j] = minimul din secv care incepe la poz i si e de lungime 2^j
int tbl[100001][20]; // log2(100000) ~ 20

int query(int left, int right)
{
	int log = logaritm[right - left + 1]; // iau cea mai mare putere a lui 2 mai mica sau egala cu lungimea query-ului

	// [ 1, 2, 3, 4, 5 ]  aici log = 2
	//   |________|
	//      |_________|   => minimul dintre 1-6 e minimul dintre 1-4 si 3-6, deci pt orice query ma folosesc doar de 2 secv => O(1) pe query

	return std::min(tbl[left][log], tbl[right - (1 << log) + 1][log]);
}

int main()
{
	f >> n >> m;
	// minimul din secv care incepe la i si e de lungime 1 (adica 2^0) e chiar elementul de pe poz i
	for (int i = 1; i <= n; ++i)
	{
		f >> tbl[i][0];
	}

	for (int i = 2; i <= n; ++i)
		logaritm[i] = 1 + logaritm[i / 2]; // calculez partea intreaga din log2 din toate nr de la 1 la n (pt query)

	for (int j = 1; j <= logaritm[n]; ++j)
		for (int i = 1; i + (1 << j) - 1 <= n; ++i)
			tbl[i][j] = std::min(tbl[i][j - 1], tbl[i + (1 << (j-1))][j - 1]);
		//	minimul din secventa care incepe la i si e de lungime 2^j este minimul dintre cele 2 jumatati de lungime 2^(j-1):
		//		minimul din secventa care incepe la i si e de lungime 2^(j-1) si
		//		minimul din secventa care incepe de la i + 2^(j-1) si e de lungime 2^(j-1)
		//		[1, 2, 3, 4, 5, 6, 7, 8]
		//		 |_________| |________|
		//		 |____________________|
		//       min dintre secv 1-8 e min( minim din secv 1-4, minim din secv 5-8)

	int x, y;
	for (int i = 0; i < m; ++i)
	{
		f >> x >> y;
		g << query(x, y) << '\n'; // -1 ca e indexat de la 0
	}
}