Cod sursa(job #3204613)

Utilizator SSKMFSS KMF SSKMF Data 17 februarie 2024 10:37:07
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.53 kb
#include <fstream>
#include <queue>
using namespace std;

ifstream cin ("heavypath.in");
ofstream cout ("heavypath.out");

struct Muchie { int nod_1 , nod_2 , urmatorul_1 , urmatorul_2; } muchii[100000];
int capat[100001] , valoare[100001] , lant[100001] , pozitie_lant[100001] , urmatorul[100001] , adancime[100001] , inceput[100001] , aparitii[100001] , arbore[400000];
queue <int> lant_actual;

void Build (const int termen , const int nod_actual , const int stanga , const int dreapta)
{
    if (stanga == dreapta) { 
        arbore[termen + nod_actual] = valoare[lant_actual.front()]; 
        lant_actual.pop(); arbore[0] = termen + nod_actual;
        return; 
    }

    const int mijloc = (stanga + dreapta) >> 1;

    Build(termen , nod_actual << 1 , stanga , mijloc);
    Build(termen , (nod_actual << 1) | 1 , mijloc + 1 , dreapta);

    arbore[termen + nod_actual] = max(arbore[termen + (nod_actual << 1)] , arbore[termen + ((nod_actual << 1) | 1)]);
}

int Distribuire (const int nod_actual , const int nod_sursa)
{
    adancime[nod_actual] = adancime[nod_sursa] + 1;
    int maxim = -1 , nod_maxim = 0 , cantitate = 1;
    for (int indice = capat[nod_actual] ; indice ; ) 
    {
        const int nod_vecin = (muchii[indice].nod_1 == nod_actual ? muchii[indice].nod_2 : muchii[indice].nod_1);
        if (nod_vecin != nod_sursa)
        {
            const int candidat = Distribuire(nod_vecin , nod_actual);
            if (candidat > maxim)
                { maxim = candidat; nod_maxim = nod_vecin; }
            
            cantitate += candidat;
        }

        if (nod_vecin == muchii[indice].nod_1) { indice = muchii[indice].urmatorul_2; }
        else { indice = muchii[indice].urmatorul_1; }
    }

    if (maxim == -1) { lant[nod_actual] = ++lant[0]; }
    else { lant[nod_actual] = lant[nod_maxim]; }

    aparitii[lant[nod_actual]]++;
    urmatorul[nod_actual] = nod_maxim;
    return cantitate;
}

void Descompunere (const int nod_actual , const int nod_sursa)
{
    lant_actual.push(nod_actual);
    pozitie_lant[nod_actual] = (lant[nod_actual] == lant[nod_sursa] ? pozitie_lant[nod_sursa] + 1 : 1);
    
    if (urmatorul[nod_actual]) { Descompunere(urmatorul[nod_actual] , nod_actual); }
    else { inceput[lant[nod_actual]] = ++arbore[0]; Build(arbore[0] - 1 , 1 , 1 , aparitii[lant[nod_actual]]); }

    for (int indice = capat[nod_actual] ; indice ; ) 
    {
        const int nod_vecin = (muchii[indice].nod_1 == nod_actual ? muchii[indice].nod_2 : muchii[indice].nod_1);
        if (nod_vecin != nod_sursa && nod_vecin != urmatorul[nod_actual])
            { Descompunere(nod_vecin , nod_actual); }

        if (nod_vecin == muchii[indice].nod_1) { indice = muchii[indice].urmatorul_2; }
        else { indice = muchii[indice].urmatorul_1; }
    } 
}

void Stabilire (const int nod_actual , const int nod_sursa)
{
    urmatorul[nod_actual] = (lant[nod_actual] == lant[nod_sursa] ? urmatorul[nod_sursa] : nod_sursa);

    for (int indice = capat[nod_actual] ; indice ; ) 
    {
        const int nod_vecin = (muchii[indice].nod_1 == nod_actual ? muchii[indice].nod_2 : muchii[indice].nod_1);
        if (nod_vecin != nod_sursa)
            { Stabilire(nod_vecin , nod_actual); }

        if (nod_vecin == muchii[indice].nod_1) { indice = muchii[indice].urmatorul_2; }
        else { indice = muchii[indice].urmatorul_1; }
    }
}

void Update (const int termen , const int nod , const int stanga , const int dreapta , const int pozitie , const int update)
{
    if (stanga == dreapta)
        { arbore[termen + nod] = update; return; }

    const int mijloc = (stanga + dreapta) >> 1;
    if (pozitie <= mijloc) { Update(termen , nod << 1 , stanga , mijloc , pozitie , update); }
    else { Update(termen , (nod << 1) | 1 , mijloc + 1 , dreapta , pozitie , update); }

    arbore[termen + nod] = max(arbore[termen + (nod << 1)] , arbore[termen + ((nod << 1) | 1)]);
}

int Query (const int termen , const int nod , const int stanga , const int dreapta , const int stanga_interval , const int dreapta_interval)
{
    if (stanga_interval <= stanga && dreapta <= dreapta_interval)
        { return arbore[termen + nod]; }

    int candidat[2] = { };
    const int mijloc = (stanga + dreapta) >> 1;
    if (stanga_interval <= mijloc) { candidat[0] = Query(termen , nod << 1 , stanga , mijloc , stanga_interval , dreapta_interval); }
    if (dreapta_interval > mijloc) { candidat[1] = Query(termen , (nod << 1) | 1 , mijloc + 1 , dreapta , stanga_interval , dreapta_interval); }
    return max(candidat[0] , candidat[1]);
}

int main ()
{
    int numar_noduri , numar_operatii;
    cin >> numar_noduri >> numar_operatii;

    for (int indice = 1 ; indice <= numar_noduri ; indice++)
        { cin >> valoare[indice]; }

    for (int indice = 1 ; indice < numar_noduri ; indice++)
    {
        cin >> muchii[indice].nod_1 >> muchii[indice].nod_2;
        muchii[indice].urmatorul_1 = capat[muchii[indice].nod_1];
        muchii[indice].urmatorul_2 = capat[muchii[indice].nod_2];
        capat[muchii[indice].nod_1] = capat[muchii[indice].nod_2] = indice;
    }

    Distribuire(1 , 0);
    Descompunere(1 , 0);
    Stabilire(1 , 0);

    while (numar_operatii--)
    {
        int tip;
        cin >> tip;

        switch (tip)
        {
            case 0:
            {
                int nod; cin >> nod >> valoare[nod];
                Update(inceput[lant[nod]] - 1 , 1 , 1 , aparitii[lant[nod]] , pozitie_lant[nod] , valoare[nod]);
            }
            break;

            case 1:
            {
                int nod_1 , nod_2;
                cin >> nod_1 >> nod_2;

                int valoare_maxima = 0;
                while (lant[nod_1] != lant[nod_2]) {
                    if (adancime[urmatorul[nod_1]] > adancime[urmatorul[nod_2]]) { valoare_maxima = max(valoare_maxima , Query(inceput[lant[nod_1]] - 1 , 1 , 1 , aparitii[lant[nod_1]] , 1 , pozitie_lant[nod_1])); nod_1 = urmatorul[nod_1]; }
                    else { valoare_maxima = max(valoare_maxima , Query(inceput[lant[nod_2]] - 1 , 1 , 1 , aparitii[lant[nod_2]] , 1 , pozitie_lant[nod_2])); nod_2 = urmatorul[nod_2]; }
                }

                valoare_maxima = max(valoare_maxima , Query(inceput[lant[nod_1]] - 1 , 1 , 1 , aparitii[lant[nod_1]] , min(pozitie_lant[nod_1] , pozitie_lant[nod_2]) , max(pozitie_lant[nod_1] , pozitie_lant[nod_2])));
                cout << valoare_maxima << '\n';
            }
            break;
        }
    }

    cout.close(); cin.close();
    return 0;
}