Cod sursa(job #2722824)

Utilizator zerolightningIon Bobescu zerolightning Data 13 martie 2021 12:24:43
Problema Arbori indexati binar Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.4 kb
#include <iostream>
#include <fstream>

using namespace std;

#define MAXN 100001
#define IPair pair<int,int>

int N, M;
IPair tree[4 * MAXN + 100];

int updateValue;
int updatePlace;

void build(int, int, int);
void update(int, int, int);

int sumStart, sumEnd;
int sum;

void sumCalc(int, int, int);

int sumToFind, rollingSum;
int k;

void sumFind(int, int, int);

int height = 0;
int capacity = 1;

int main()
{
	ifstream f("aib.in");
	ofstream g("aib.out");
	// Program
	f >> N >> M;
	
	int cN = N;
	bool up = false;
	if (cN % 2 == 1) up = true;
	while (cN >>= 1)
	{
		if (cN != 1 && cN % 2 == 1) up = true;
		++height;
	}
	if (up) ++height;

	while (height)
	{
		capacity *= 2;
		height--;
	}

	for (int i = 1; i <= N; i++)
	{
		f >> updateValue;
		updatePlace = i;
		build(1, 1, N);
	}
	for (int i = 0; i < M; i++)
	{
		int c, a, b;
		f >> c;
		if (c == 0)
		{
			f >> a >> b;
			updatePlace = a;
			updateValue = b;
			update(1, 1, N);
		}
		else if (c == 1)
		{
			f >> a >> b;
			sumStart = a;
			sumEnd = b;
			sum = 0;
			sumCalc(1, 1, N);
			g << sum << '\n';
		}
		else
		{
			f >> a;

			sumToFind = a;
			rollingSum = 0;
			k = 0;

			sumFind(1, 1, N);

			g << k <<'\n';
		}
	}


	// Exit
	f.close();
	g.close();
	return 0;
}

IPair add(IPair a, IPair b)
{
	return make_pair(a.first + b.first, a.second + b.second);
}

void build(int treePlace, int treeStart, int treeEnd)
{
	if (treeStart == treeEnd)
	{
		tree[treePlace] = make_pair(updateValue,1);
		return;
	}

	int mij = (treeStart + treeEnd) / 2;
	if (updatePlace <= mij) build(2 * treePlace, treeStart, mij);
	else build(2 * treePlace + 1, mij + 1, treeEnd);

	tree[treePlace] = add(tree[2 * treePlace], tree[2 * treePlace + 1]);
}
void update(int treePlace, int treeStart, int treeEnd)
{
	if (treeStart == treeEnd)
	{
		tree[treePlace].first += updateValue;
		return;
	}

	int mij = (treeStart + treeEnd) / 2;
	if (updatePlace <= mij) update(2 * treePlace, treeStart, mij);
	else update(2 * treePlace + 1, mij + 1, treeEnd);

	tree[treePlace].first = tree[2 * treePlace].first + tree[2 * treePlace + 1].first;
}

void sumCalc(int treePlace, int treeStart, int treeEnd)
{
	if (sumStart <= treeStart && treeEnd <= sumEnd)
	{
		sum += tree[treePlace].first;
		return;
	}
	
	int mij = (treeStart + treeEnd) / 2;
	if (sumStart <= mij) sumCalc(2 * treePlace, treeStart, mij);
	if (mij + 1 <= sumEnd) sumCalc(2 * treePlace + 1, mij + 1, treeEnd);
}
void sumFind(int treePlace, int treeStart, int treeEnd)
{
	if (rollingSum + tree[treePlace].first == sumToFind)
	{
		k += tree[treePlace].second;
		return;
	}

	
	if (tree[treePlace].first >= (sumToFind-rollingSum))
	{
		try
		{
			if (tree[2*treePlace].first == 0)
			{
				k = -1;
				return;
			}
		}
		catch (const std::exception&)
		{
				k = -1;
				return;
		}

		sumFind(2 * treePlace, treeStart, treeEnd);
	}
	else //if (tree[treePlace] < sumToFind)
	{
		//     *
		//   /  \
		//  h    e
		if (treePlace == 0)
		{
			k = -1;
			return; // we have the highset sum, nothing to do
		}
		if (tree[treePlace].second == 1 && treePlace % 2 == 1)
		{
			k = -1;
			return; // we are a leaf and on the right and we want to go right... no can do
		}
		k += tree[treePlace].second;
		rollingSum += tree[treePlace].first;

		sumFind(treePlace + 1, treeStart, treeEnd);

	}
}