Cod sursa(job #2530266)

Utilizator nicolaefilatNicolae Filat nicolaefilat Data 24 ianuarie 2020 16:27:11
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.45 kb
#include <iostream>
#include <fstream>
#include <vector>

const int MAXN = 1e5 + 5;

using namespace std;

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

/// nod_lant[i] = in ce lant se afla nodul i
/// pozitie[i] = pe ce pozitie se afla in lantul (deja stiut) nodul i
/// inaltime[i] = care este inaltimea lantului care se afla pe pozitia i
/// daca am lantul pe ex : 4 3 2 1(e luat de la spate in fata din cauza la dfs)
/// atunci nod_lant[4] = nod_lant[3] = nod_lant[2] = nod_lant[1] = 1 primul lant
/// pozitie[4] = 1 in lant se alfa pe poz 1, pozitie[3] = 2, pozitie[2] = 3, pozitie[1] = 4
/// inaltime[1] = 1, se afla la inaltimea 1, dar lantul 9 8 7 se afla la inaltimea 2
/// daca citeste cineva asta sper sa inteleaga :)
/// singurul vector indexat de la 0 este lant[i]

int tata[MAXN],dimensiune[MAXN],nod_lant[MAXN],pozitie[MAXN],inaltime[MAXN];
int valori[MAXN];


bool viz[MAXN];
int nr_lanturi;
vector<int>arbore_intervale[MAXN];/// Sunt indexati de la 1!!!!!


vector<int>lant[MAXN];/// indexati de la 0!!
vector<int>graf[MAXN];

void dfs(int nod,int anterior = -1){
    dimensiune[nod] = 1;
    viz[nod] = true;
    int curent;
    for(int i = 0; i < graf[nod].size(); i++){
        curent = graf[nod][i];
        if(curent == anterior){
            /// anteriorul este nodul care a fost parcurs inainte
            /// daca eu vreau sa ma duc cu o muchie in spate atunci tatal nodului curent este anterior
            tata[nod] = anterior;
        }
        if(!viz[curent]){
            dfs(curent,nod);
            dimensiune[nod] += dimensiune[curent];
        }

    }

    if(graf[nod].size() == 1 && nod != 1){
        lant[++nr_lanturi].push_back(nod);
        nod_lant[nod] = nr_lanturi;
        pozitie[nod] = 1; /// il pun pe pozitia 1
    }else{
        int vecin_bun,maxim = 0;
        for(int i = 0; i < graf[nod].size(); i++){
            int curent = graf[nod][i];
            if(dimensiune[curent] > maxim && curent != anterior){
                vecin_bun = curent;
                maxim = dimensiune[curent];
            }
        }
        int unde = nod_lant[vecin_bun];
        lant[unde].push_back(nod); /// adaug nodul nod la lantul cu subarborele maxim
        nod_lant[nod] = unde;
        pozitie[nod] = lant[unde].size();/// il pun pe ultima pozitie

        for(int i = 0; i < graf[nod].size(); i++){
            int curent = graf[nod][i];
            if(nod_lant[curent] != nod_lant[nod])
                inaltime[nod_lant[curent]] = inaltime[nod_lant[nod]] + 1; /// modific inaltimea lantului
        }
    }
}
void update(int index_lant,int val,int pozitie,int st,int dr,int nod = 1){
    ///cout<<st<<" "<<dr<<" "<<pozitie<<" "<<nod<<endl;
    if(st == dr && st == pozitie){
        arbore_intervale[index_lant][nod] = val;
        return;
    }
    int mij = (st + dr)  / 2;
    if(pozitie <= mij)
        update(index_lant,val,pozitie,st,mij,nod * 2);
    else
        update(index_lant,val,pozitie,mij + 1,dr,nod * 2 + 1);
    if(nod * 2 + 1 < arbore_intervale[index_lant].size()) /// sa nu cumva sa ies din size
        arbore_intervale[index_lant][nod] = max(arbore_intervale[index_lant][nod * 2],arbore_intervale[index_lant][nod * 2 + 1]);
}
int query(int index_lant,int query_left,int query_right,int st,int dr,int nod = 1){
    ///cout<<st<<" "<<dr<<" "<<nod<<" "<<arbore_intervale[index_lant][nod]<<endl;
    if(query_left <= st && dr <= query_right)
        return arbore_intervale[index_lant][nod];
    int mij = (st + dr) / 2;
    int val_stanga = 0,val_dreapta = 0;
    if(query_left <= mij)
        val_stanga = query(index_lant,query_left,query_right,st,mij,nod * 2);
    if(mij + 1 <= query_right)
        val_dreapta = query(index_lant,query_left,query_right,mij + 1,dr,nod * 2 + 1);

    return max(val_stanga,val_dreapta);
}
int query_lant(int nod){
    int index_lant = nod_lant[nod];
    int dimensiune = lant[index_lant].size();
    int poz = pozitie[nod];/// pozitie e de la 1 indexat
    return query(index_lant,poz,dimensiune,1,dimensiune);
}
int intrebare(int a,int b){
    /// calculez usor usor lca intre a si b
    if(inaltime[nod_lant[a]] < inaltime[nod_lant[b]])
        swap(a,b);
    /// a este intr-un lant mai sus decat b
    int maxim = max(query_lant(a),query_lant(b));
    while(inaltime[nod_lant[a]] > inaltime[nod_lant[b]]){
        int urmatorul = lant[nod_lant[a]].back();/// ultimul element
        a = tata[urmatorul];
        maxim = max(maxim,query_lant(a));
    }
    /// sunt pe aceasi inaltime
    while(nod_lant[a] != nod_lant[b]){
        int urmatorul = lant[nod_lant[a]].back();
        a = tata[urmatorul];
        maxim = max(maxim,query_lant(a));
        urmatorul = lant[nod_lant[b]].back();
        b = tata[urmatorul];
        maxim = max(maxim,query_lant(b));
    }

    /// sunt in acelasi lant
    /// eu vreau ca a sa fie mai jos pe lant
    /// vectorul de pozitii este pe invers adica pt lantul 4 3 2 1, poz : 1 2 3 4
    /// vreau ca poz[a] < poz[b] daca nu, fac este swap(a,b)
    ///cout<<a<<" "<<b<<" "<<" pozitii : "<<pozitie[a]<<" "<<pozitie[b]<<endl;
    if(pozitie[a] > pozitie[b])
        swap(a,b);
    int query_pe_lant = query(nod_lant[a],pozitie[a],pozitie[b],1,lant[nod_lant[a]].size());
    maxim = max(maxim,query_pe_lant);
    /// acum stiu clar ca a = b;
    out<<maxim<<"\n";
}

void construieste_arbore(int index_lant){
    vector<int>arbore(4 * lant[index_lant].size() + 2);

    arbore_intervale[index_lant] = arbore;
    int lung_lant = lant[index_lant].size();
    for(int i = 0; i < lant[index_lant].size(); i++){
        int val = valori[lant[index_lant][i]];
        update(index_lant,val,i + 1,1,lung_lant);/// !! indexati de la 1 de aia poz = i + 1
    }
}



int main()
{
    int n,intrebari;
    in>>n>>intrebari;
    for(int i = 1; i <= n; i++)
        in>>valori[i];
    for(int i = 1; i <= n - 1; i++){
        int x,y;
        in>>x>>y;
        graf[x].push_back(y);
        graf[y].push_back(x);
    }
    inaltime[1] = 1;
    dfs(1);
    for(int i = 1; i <= n; i++)
        construieste_arbore(i);
    for(int i = 1; i <= intrebari; i++){
        int cerinta,a,b;
        in>>cerinta>>a>>b;
        if(cerinta == 1){
            intrebare(a,b);
        }else{
            int index_lant = nod_lant[a];
            int pozitie_lant = pozitie[a];
            update(index_lant,b,pozitie_lant,1,lant[index_lant].size());
        }
    }
    return 0;
}