Cod sursa(job #2906012)

Utilizator neagamariaMaria Neaga-Budoiu neagamaria Data 24 mai 2022 19:00:23
Problema Heapuri cu reuniune Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.13 kb
#include <iostream>
#include <fstream>
#include <cmath>

using namespace std;

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

struct nod
{
    nod *st;
    nod *dr;
    nod *parinte;
    nod *partener;
    nod *copil;

    long long cheie;
    long long dim;
    bool de_ech;
};

struct heap
{
    nod **arbori;
    int max_arbori;
    int nr_noduri;
    long long val;
};

void initializareHeap(heap *H, int max_noduri)
{
    H->max_arbori=(int)(log(max_noduri+1)/log(2.0));
    H->arbori=new nod*[H->max_arbori+1];
    H->nr_noduri=H->val=0;

    for (int i=0; i<H->max_arbori; i++)
    {
        H->arbori[i]=NULL;
    }
}

nod *creareNod(long long cheie)
{
    nod *n=new nod();
    n->cheie=cheie;
    n->dim=0;
    n->de_ech=false;
    n->copil=n->parinte=n->partener=n->st=n->dr=NULL;

    return n;
}

void adaugareNodCopil(nod *h, nod *n)
{
    nod *st, *dr;

    st = h->copil;
    if (st != NULL)
    {
        dr=st->dr;
        n->st=st;
        n->dr=dr;
        dr->st=n;
        st->dr=n;
    }
    else
    {
        n->st=n->dr=n;
    }

    h->copil=n;
    n->parinte=h;
}

int mergeNoduri(nod **a, nod **b)
{
    nod *arbore, *urm, *alt, *urm_alt;

    int c=0;

    //merge alt in arbore, in functie de cheie
    if ((*a)->cheie>=(*b)->cheie)
    {
        arbore=(*a);
        alt=(*b);
    }
    else {
        arbore=(*b);
        alt=(*a);
    }
    c++;

    urm=arbore->partener;
    urm_alt=alt->partener;

    if (urm==NULL)
    {
        if (urm_alt!=NULL)
        {
            adaugareNodCopil(arbore, alt);
            (arbore->dim)++;

            (*a)=NULL;
            (*b)=arbore;
        }
        else
        {
            arbore->partener=alt;
            alt->partener=arbore;
            alt->de_ech=true;

            (*a)=arbore;
            (*b)=NULL;
        }
    }
    else if(urm_alt==NULL)
    {
        arbore->partener=NULL;
        alt->partener=urm;
        urm->partener=alt;

        if (alt->cheie>urm->cheie)
        {
            adaugareNodCopil(arbore, alt);
        }
        else
        {
            urm->de_ech=false;
            alt->de_ech=true;
            adaugareNodCopil(arbore, urm);
        }

        (arbore->dim)++;

        c++;
        (*a)=NULL;
        (*b)=arbore;
    }
    else
    {
        arbore->partener=NULL;
        urm->partener=NULL;
        urm->de_ech=false;
        urm->st=urm->dr=urm;
        urm->parinte=NULL;

        adaugareNodCopil(arbore, alt);
        (arbore->dim)++;

        (*a)=urm;
        (*b)=arbore;
    }

    return c;
}

void aranjareHeap(heap *H, nod *lista)
{
    nod *urm, *de_aranjat, *de_mutat;
    long long d;

    de_aranjat=lista;
    de_mutat=NULL;

    do
    {
        if (de_aranjat!=NULL)
        {
            urm=de_aranjat->dr;
            de_aranjat->dr=de_aranjat->st=de_aranjat;
            de_aranjat->parinte=NULL;
        }
        else
        {
            de_aranjat=de_mutat;
            de_mutat=NULL;
        }

        if (de_mutat!=NULL)
        {
            mergeNoduri(&de_aranjat, &de_mutat);
        }

        if (de_aranjat!=NULL)
        {
            d=de_aranjat->dim;
            if (H->arbori[d]!=NULL)
            {
                mergeNoduri(&(H->arbori[d]), &de_aranjat);
                if(H->arbori[d]==NULL)
                    H->val-=(1<<d);
                de_mutat=de_aranjat;
            }
            else
            {
                H->arbori[d]=de_aranjat;
                H->val+=(1<<d);
            }
        }

        de_aranjat=urm;
    }
    while (de_aranjat!=NULL || de_mutat!=NULL);
}

nod *inserare(heap *H, long long cheie)
{
    nod *n=creareNod(cheie);
    aranjareHeap(H, n);
    H->nr_noduri ++;

    return n;
}

nod *aflareNodMax(heap *H)
{
    nod *nod_max, *urm;
    long long k, k2;
    long long r, v;

    v=H->val;
    r=-1;
    while(v!=0)
    {
        v =v>>1;
        r++;
    }

    nod_max=H->arbori[r];
    k=nod_max->cheie;

    while (r>0)
    {
        r--;
        urm=H->arbori[r];
        if (urm)
        {
            if((k2=urm->cheie) > k)
            {
                k=k2;
                nod_max=urm;
            }
        }
    }

    return nod_max;
}

void stergereMax(heap *H, nod *nod_max)
{
    nod *copil, *urm, *partener;

    long long r=nod_max->dim;
    if ((partener=nod_max->partener))
    {
        partener->partener=NULL;
        partener->parinte=NULL;
        partener->st=partener->dr=partener;
        H->arbori[r]=partener;
    }
    else
    {
        H->arbori[r]=NULL;
        H->val-=(1<<r);
    }
    H->nr_noduri--;

    copil=nod_max->copil;
    if (copil)
    {
        urm=copil->dr;
        urm->st=copil->dr=NULL;
        aranjareHeap(H, urm);
    }
}

bool mergeHeap(heap *H1, heap *H2)
{
    for (int i=0; i<H2->max_arbori; i++)
    {
        if (H2->arbori[i]!=NULL)
        {
            H2->arbori[i]->dr=H2->arbori[i]->st=NULL;
            aranjareHeap(H1, H2->arbori[i]);
            H2->arbori[i]=NULL;
        }
    }
    H1->nr_noduri+=H2->nr_noduri;
    H2->nr_noduri=0;

    return true;
}

int main()
{
    int n, q, op;

    in>>n>>q;

    heap *H[n+1];
    for(int i=1; i<=n; i++)
    {
        H[i] = new heap;
        initializareHeap(H[i], 500000);
    }

    int nr_heap, nr_heap2;
    long long cheie_nod;
    nod *nod_max;

    for(int i=0; i<q; i++)
    {
        in>>op;
        switch(op)
        {
            case 1: //inserare
                in>>nr_heap>>cheie_nod;
                inserare(H[nr_heap], cheie_nod);
                break;
            case 2: //stergere maxim
                in>>nr_heap;
                nod_max = aflareNodMax(H[nr_heap]);
                out<<nod_max->cheie<<'\n';
                stergereMax(H[nr_heap], nod_max);
                break;
            case 3: //merge
                in>>nr_heap>>nr_heap2;
                mergeHeap(H[nr_heap], H[nr_heap2]);
                break;
        }
    }

    return 0;
}