Cod sursa(job #322501)

Utilizator tomescu_alinTomescu Alin tomescu_alin Data 8 iunie 2009 22:55:32
Problema Heapuri Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.58 kb
#include <iostream>
#include <fstream>
#include <cassert>
using namespace std;

typedef unsigned long ulong;

const ulong MAX_OPERATIONS = 200000+1;

class SpecialHeap 
{
	public:
		SpecialHeap()
			:	heapSize(0), indexCounter(0)
		{}
	
	public:
		//	Pushes a new number on the heap
		void push(ulong number);
		//	Pops the number with that index off the heap
		void pop(ulong id);
		//	Returns the min. number in the heap
		ulong peek() const;
	
	private:
		//	Internal heap array related operations
		ulong getParent 	(ulong index) const { return (index-1)/2; }
		ulong getLeftChild 	(ulong index) const { return 2*index+1; }
		ulong getRightChild	(ulong index) const { return 2*index+2; }
		
		bool hasLeftChild 	(ulong index) const { return 2*index+1 < heapSize; }	
		bool hasRightChild 	(ulong index) const { return 2*index+2 < heapSize; }
		bool hasChildren	(ulong index) const { return hasLeftChild(index); }
		
		bool isRoot		(ulong index) const { return index == 0; }
		bool hasParent	(ulong index) const { return !isRoot(index); }
	
	private:
		ulong value(ulong id) const { return idToNumber[id]; }
		bool areMappingsValid() const;
	
	private:
		//	Each number is going to have an index or key or whatever you want to call it.
		//	The value of a number's index is the time (expressed as a number) when that
		//	number was inserted into the heap.
		//	Example:
		//		The index for the firstly inserted item is 0
		//		The index for the secondly inserted item is 1
		//		And so on, the index for the n'th inserted item is n-1		
		
		//	Maps an index to a number. This is where the actual numbers are stored.
		ulong idToNumber[MAX_OPERATIONS];
		
		//	Maps an index to its position in the internal heap array.
		//	(We need this for fast lookup when removing from the heap)
		ulong idToHeapPos[MAX_OPERATIONS];
		
		//	Keeps a min-heap of the numbers but instead of storing the values it stores their indices
		ulong heapOfIds[MAX_OPERATIONS];
	
		ulong heapSize;		//	The current number of elements in the heap
		ulong indexCounter;	//	The current index counter (this goes from 0 to inf)	
};

bool SpecialHeap::areMappingsValid() const
{
	// for(int i = 0; i < heapSize; i++)
	// {
		// if(heapOfIds[idToHeapPos[i]] != i)
			// return false;
	// }
	return true;
}

ulong SpecialHeap::peek() const 
{
	return idToNumber[heapOfIds[0]];
}

void SpecialHeap::push(ulong number)
{
	//	Store the number in the id-to-number map
	ulong id = indexCounter++;
	idToNumber[id] = number;
	
	//	Now we need to actually put that number's id in the heap
	
	//	So we start by putting it at the "end" of the heap-array
	ulong heapIndex = heapSize++;
	heapOfIds[heapIndex] = id;
	idToHeapPos[id] = heapIndex;
	
	//	And then we sift it up...
	//	But each time we swap an element while sifting we need to update
	//	our 'idToHeapPos' array with the new mapping
	while(hasParent(heapIndex))
	{
		ulong parentHeapIndex = getParent(heapIndex);
		ulong parentId = heapOfIds[parentHeapIndex];
		if(value(id) < value(parentId))
		{
			//	Swap the two...
			std::swap(heapOfIds[heapIndex], heapOfIds[parentHeapIndex]);
			std::swap(idToHeapPos[id], idToHeapPos[parentId]);
			
			heapIndex = parentHeapIndex;
		}
		else
		{
			break;
		}
	}
	
	assert(areMappingsValid());
}

void SpecialHeap::pop(ulong deletedId)
{
	ulong lastId = heapOfIds[heapSize-1];
	ulong heapIndex = idToHeapPos[deletedId];
	
	//	Replace the deleted element with the last one in the heap
	heapOfIds[heapIndex] = lastId;
	heapSize--;
	
	//	Update the id-to-heap-pos mapping
	idToHeapPos[lastId] = heapIndex;
	
	
	while(hasChildren(heapIndex))
	{
		//	If one of the element's children is smaller 
		//	than the element, then we need to swap the two
		
		//	Get the minimum child.
		//	We know there's a left child 
		//	since that's the precondition for the loop.
		ulong childHeapIndex = getLeftChild(heapIndex);
		ulong childId = heapOfIds[childHeapIndex];
		
		if(hasRightChild(heapIndex))
		{
			//	Compare the two and store the minimum one...
			ulong rightChildHeapIndex = getRightChild(heapIndex);
			ulong rightChildId = heapOfIds[rightChildHeapIndex];
			
			if(value(rightChildId) < value(childId))
			{
				childHeapIndex = rightChildHeapIndex;
				childId = rightChildId;
			}
		}
		
		if(value(childId) < value(lastId))
		{
			//	Swap with the minimum
			std::swap(heapOfIds[heapIndex], heapOfIds[childHeapIndex]);
			std::swap(idToHeapPos[lastId], idToHeapPos[childId]);
			
			heapIndex = childHeapIndex;
		}
		else 
		{
			break;
		}
	}
	
	assert(areMappingsValid());
}

int main()
{
	const char * inFile = "heapuri.in";
	const char * outFile = "heapuri.out";
	
	ulong nOperations;
	ulong x;
	
	ifstream fin(inFile);
	ofstream fout(outFile);
	
	if(!fin) {
		cout << "Error opening file: " << inFile << endl;
		return 0;
	} else {
		cout << "Successfully opened file: " << inFile << endl;
	}

	fin >> nOperations;
	
	// Our "special" heap suited for this task
	SpecialHeap * heap = new SpecialHeap;
	
	for(ulong i = 0; i < nOperations; i++)
	{
		ulong op;
		long number = -1;
		
		fin >> op;
		assert(op >= 1 && op <= 3);
		switch(op)
		{
			case 1:
			{
				fin >> number;
				assert(number >= 0);
				heap->push(number);
				break;
			}
			case 2:
			{
				fin >> number;
				// Our id mapping is off by one for convenience...
				assert(number >= 0);
				heap->pop(number-1);
				break;
			}
			case 3:
			{
				fout << heap->peek() << "\n";
				break;
			}
		}
	}
	
	fout.close();
	fin.close();
	
	return 0;
}