Cod sursa(job #1121581)

Utilizator fhandreiAndrei Hareza fhandrei Data 25 februarie 2014 13:16:58
Problema Arbori indexati binar Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 2.65 kb
// Include
#include <fstream>
using namespace std;

// Constante
const int sz = (int)1e5+1;

// Functii
inline int leastSignificantBit(int x);
void update(int pos, int val); // Valoarea elementului de pe pozitia pos creste cu val
int query(int pos); // Afla suma de pe intervalul [1, pos]
int search(int val); // Afla, prin cautare binara, pozitia pos astfel incat suma de pe intervalul [1, pos] este egala cu val

// Variabile
ifstream in("aib.in");
ofstream out("aib.out");

int num;
int questions, type;

int tree[sz];

// Main
int main()
{
	in >> num >> questions;
	int val;
	for(int i=1 ; i<=num ; ++i)
	{
		in >> val;
		update(i, val);
	}
	
	while(questions--)
	{
		in >> type;
		
		switch(type)
		{
			case 0:
			{
				int pos, val;
				in >> pos >> val;
				update(pos, val);
				break;
			}
			case 1:
			{
				int left, right;
				in >> left >> right;
				out << query(right) - query(left-1) << '\n';
				break;
			}
			case 2:
			{
				int val;
				in >> val;
				out << search(val) << '\n';
				break;
			}
		}
	}
	
	in.close();
	out.close();
	return 0;
}

void update(int pos, int val)
{
	// La fieccare pas, pozitia creste cu cel mai nesemnificant bit.
	// In acest mod voi ajunge la o pozitie a carei suma contine si valoarea de pe pozitia initiala pos
	for(; pos<=num ; pos+=leastSignificantBit(pos))
		// Valoarea de pe actuala pozitie pos creste cu val
		tree[pos] += val;
}

int query(int pos)
{
	// Suma de pe intervalul [1, pos]
	int sum = 0;
	// La fieccare pas, pozitia scade cu cel mai nesemnificant bit.
	// In acest mod voi ajunge la o pozitie a carei suma contine si valoarea de pe pozitia initiala pos
	for(; pos ; pos&=pos-1)
		sum += tree[pos];
	
	return sum;
}

inline int leastSignificantBit(int x)
{
	return x ^ (x&(x-1));
}

int search(int val)
{
	// Capetele intervalului curent
	int left = 1, right = num;
	
	// Caut in intervalul [left, right] atat timp cat intervalul contine cel putin un element (atat timp cat mai exista intervalul)
	while(left <= right)
	{
		// Mijlocul intervalului
		int mid = (left + right) / 2;
		
		// Suma de pe intervalul [1, mid]
		int midVal = query(mid);
		
		// Daca valoarea din mijloc este chiar valoarea cautata, inseamna ca pozitia cautata este chiar mijlocul
		if(midVal == val)
			return mid;
			
		// In caz contrar, ma uit in care dintre cele doua intervale ([left, mid-1] sau [mid+1, right]) trebuie sa caut
		if(val < midVal)
			right = mid-1;
		else
			left = mid+1;
	}
	
	// Daca am ajuns aici (la un interval nul), inseamna ca nu exista pos astfel incat suma de pe intervalul [1, pos] sa fie val
	return -1;
}