Cod sursa(job #2749157)

Utilizator cristivasileVasile George-Cristian cristivasile Data 5 mai 2021 14:52:18
Problema Heapuri cu reuniune Scor 70
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.41 kb
#include <iostream>
#include <fstream>
#include <list>

using namespace std;

ifstream f("mergeheap.in");
ofstream g("mergeheap.out");

struct Nod {
    int val, grad;
    Nod* copil, * frate, * parinte;
};

Nod* newNod(int x) {    //se creeaza un nod nou
    Nod* newNod = new Nod;
    newNod->grad = 0;
    newNod->val = x;
    newNod->copil = NULL;
    newNod->frate = NULL;
    newNod->parinte = NULL;
    return newNod;
}

class BinomialHeap {
    list <Nod*> heap;

public:

    void deleteRadacina(Nod* min) {     //se elimina radacina unui tree si se "distribuie" copii in heap

        if (min->grad == 0) {
            delete min;
            return;
        }

        Nod* del = min;

        min->copil->parinte = NULL;
        heap.push_front(min->copil);

        min = min->copil;
        while (min->frate) {
            min->frate->parinte = NULL;
            heap.push_front(min->frate);
            min = min->frate;
        }

        delete del;
    }

    Nod* mergeTrees(Nod* t1, Nod* t2) {     //se merge-uiesc 2 binary trees

        if (t1->val < t2->val) {
            Nod* aux;
            aux = t1;
            t1 = t2;
            t2 = aux;
        }

        t2->frate = t1->copil;
        t1->copil = t2;
        t2->parinte = t1;
        t1->grad++;

        return t1;
    }

    void reHeap() {     //se repara proprietatea de binomial heap, adica se unesc toti arborii care au acelasi grad
        list <Nod*> ::iterator pred, curr, next, del;

        if (heap.size() <= 1)
            return;

        pred = heap.begin();
        curr = pred;
        curr++;
        next = curr;

        if (next != heap.end())
            next++;

        while (curr != heap.end()) {

            if ((*pred)->grad < (*curr)->grad) { //daca arborii au grad diferit => nu se pot uni
                pred++;
                curr++;
                if (next != heap.end())
                    next++;
            }
            else if ((*pred)->grad == (*curr)->grad) {     //daca arborii curenti au acelasi grad

                if (next != heap.end() && ((*pred)->grad == (*next)->grad)) {   //daca si arborele urmator are acelasi grad vrem sa avansam, pentru a le uni pe ultimele 2
                    pred++;
                    curr++;
                    next++;
                }

                else {                                                          //altfel, se unesc arborii curenti
                    *pred = mergeTrees(*pred, *curr);
                    del = curr;                                                 //se sterge arborele 2 dupa ce se avanseaza pozitia
                    curr++;
                    heap.erase(del);
                    if (next != heap.end())
                        next++;
                }
            }
        }
    }

    void meld(BinomialHeap& heap2) {   //se meld-uieste un binomial heap la binomial heap-ul curent

        list <Nod*> ::iterator h1 = heap.begin();
        list <Nod*> ::iterator h2 = heap2.heap.begin();

        list <Nod*> newHeap;

        //algoritm de interclasare, in functie de gradurile arborilor din fiecare heap
        while (h1 != heap.end() && h2 != heap2.heap.end()) {
            if ((*h1)->grad <= (*h2)->grad) {
                newHeap.push_back(*h1);
                h1++;
            }
            else {
                newHeap.push_back(*h2);
                h2++;
            }
        }

        while (h1 != heap.end()) {
            newHeap.push_back(*h1);
            h1++;
        }

        while (h2 != heap2.heap.end()) {
            newHeap.push_back(*h2);
            h2++;
        }

        heap = newHeap;     //se pune heap-ul rezultat in binomial heap-ul #1
        reHeap(); // se ruleaza algoritmul care uneste arborii de acelasi grad pe heap-ul rezultat

        heap2.heap.clear(); //se sterge binomial heap-ul #2
    }


    list <Nod*> ::iterator getRadacina() {        //se returneaza nodul care contine minimul
        list <Nod*> ::iterator itm;
        Nod* min = newNod(-999999999);

        for (list <Nod*> ::iterator it = heap.begin(); it != heap.end(); it++) {
            if ((*it)->val > min->val) {
                min = *it;
                itm = it;
            }
        }

        return itm;
    }

    int top() {
        return (*getRadacina())->val;
    }

    void push(int x) {
        Nod* newTree = newNod(x);
        heap.push_front(newTree);
        reHeap();
    }

    void pop() {
        list <Nod*> ::iterator radacina = getRadacina();

        BinomialHeap newHeap;   //se creeaza un heap nou

        newHeap.deleteRadacina(*radacina);  //se pun copii tree-ului care contine minimul in heap-ul nou

        heap.erase(radacina);   //se sterge tree-ul care contine minimul din heap

        meld(newHeap);  //se insereaza copii tree-ului in heap
    }

};

int N, M;
BinomialHeap Heap[101];

int main()
{
    f >> N >> M;

    int task, h, x, h1, h2;
    for (int i = 1; i <= M; ++i) {
        f >> task;

        if (task == 1) {

            f >> h >> x;
            Heap[h].push(x);

        }
        if (task == 2) {

            f >> h;
            g << Heap[h].top() << '\n';
            Heap[h].pop();
        }
        if (task == 3) {

            f >> h1 >> h2;
            Heap[h1].meld(Heap[h2]);
        }
    }

    return 0;
}