Cod sursa(job #2536371)

Utilizator nicolaefilatNicolae Filat nicolaefilat Data 1 februarie 2020 20:57:26
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.12 kb
#include <iostream>
#include <fstream>
#include <vector>

const int MAXN = 1e5 + 1;

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!!!!!

int maxim;/// raspunsul la intrebare

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
    }
}
void dfs_inaltimi(int nod){
    viz[nod] = true;
    for(auto vecin : graf[nod]){
        if(!viz[vecin]){
            int unde_nod = nod_lant[nod],unde_vecin = nod_lant[vecin];
            if(unde_nod != unde_vecin)
                inaltime[unde_vecin] = inaltime[unde_nod] + 1;
            dfs_inaltimi(vecin);
        }
    }
}
void update(int index_lant,int val,int pozitie,int st,int dr,int nod = 1){
    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){
    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];
    return query(index_lant,poz,dimensiune,1,dimensiune);
}
void intrebare(int a,int b){
    if(nod_lant[a] == nod_lant[b]){
        int index = nod_lant[a];
        /// iau maximul de pe lantul a
        int mn_poz = min(pozitie[a],pozitie[b]);
        int mx_poz = max(pozitie[a],pozitie[b]);
        maxim = max(maxim,query(nod_lant[a],mn_poz,mx_poz,1,lant[index].size()));
        return;
    }
    /// vreau h[a] > h[b]

    if(inaltime[nod_lant[a]] < inaltime[nod_lant[b]])
        swap(a,b);
    if(inaltime[nod_lant[a]] > inaltime[nod_lant[b]]){
        maxim = max(maxim,query_lant(a));
        int sf = lant[nod_lant[a]].back();
        intrebare(tata[sf],b);
    }else if(inaltime[nod_lant[a]] == inaltime[nod_lant[b]]){
        maxim = max(maxim,query_lant(a));
        int sf_a = lant[nod_lant[a]].back();
        maxim = max(maxim,query_lant(b));
        int sf_b = lant[nod_lant[b]].back();
        intrebare(tata[sf_a],tata[sf_b]);
    }
}

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

    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++)
        viz[i] = false;
    dfs_inaltimi(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){
            maxim = 0;
            intrebare(a,b);
            out<<maxim<<"\n";
        }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;
}