Cod sursa(job #2762637)

Utilizator NeacsuMihaiNeacsu Mihai NeacsuMihai Data 9 iulie 2021 00:22:23
Problema Heavy Path Decomposition Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 6.15 kb
/*
    Sursa experimentala, inca nu sunt foarte convins de ce am facut
*/
#include <iostream>
#include <fstream>
#include <vector>

#define MAXLANT 100 //??
#define NMAX 100000 //o suta de mii
#define LOG_EUL 17

using namespace std;

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

int nrLanturi;
int dim_eul;

int smNod[NMAX + 1];
vector <int> v[NMAX + 1];

int val[NMAX + 1];

int lant[NMAX + 1];
int dimensiuneLant[MAXLANT + 1];
int posLant[NMAX + 1];
int tataLant[MAXLANT + 1];

int tt[NMAX + 1];

int tree[MAXLANT + 1][4 * NMAX + 1];

int eul[2 * NMAX];
int firstEul[NMAX + 1];
int RMQ[LOG_EUL][2 * NMAX];

/////////////////////

inline void adaugareEul(int node){
    dim_eul++;
    eul[dim_eul] = node;
}
/////////////////////

void DFS(int node, int tata){
    //printf("DFS(%d, %d)\n", node, tata);

    adaugareEul(node);
    firstEul[node] = dim_eul;

    smNod[node] = 1;

    int MX = -1;
    int fiuMx;
    for(int i = 0; i < v[node].size(); i++){
        int vec = v[node][i];

        if(vec != tata){
            DFS(vec, node);

            smNod[node] += smNod[vec];

            if(smNod[vec] > MX){
                MX = smNod[vec];
                fiuMx = vec;
            }

            adaugareEul(node);
        }
        else {
            tt[node] = vec;
        }
    }

    if(MX == -1){
        //este frunza, creez un nou lant
        nrLanturi++;
        lant[node] = nrLanturi;
        dimensiuneLant[nrLanturi] = 1;
        tataLant[ lant[node] ] = node;

        //printf("%d este frunza!\n", node);
    }
    else {
        //adaug node la lantul din care face parte fiuMx
        lant[node] = lant[fiuMx];
        dimensiuneLant[ lant[node] ] ++;
        tataLant[ lant[node] ] = node;
    }
}
/////////////////////

void buildPos(int node, int tata){
    if(lant[node] == lant[tata]){
        posLant[node] = posLant[tata] + 1;
    }
    else {
        posLant[node] = 1;
    }

    for(int i = 0; i < v[node].size(); i++){
        int vec = v[node][i];

        if(vec != tata){
            buildPos(vec, node);
        }
    }
}
/////////////////////

void computeRMQ(){
    for(int i = 1; i <= dim_eul; i++){
        RMQ[0][i] = eul[i];
    }

    for(int j = 1; (1 << j) <= dim_eul; j++){
        for(int i = 1; i - 1 + (1 << j) <= dim_eul; i++){
            RMQ[j][i] = min(RMQ[j - 1][i], RMQ[j - 1][i + (1 << (j - 1))]);
        }
    }
}
/////////////////////

int putereDoiLowerbound(int X){
    int pt = 0;

    while( (1 << pt) <= X ){
        pt++;
    }

    return pt - 1;
}
/////////////////////

int minimRMQ(int left, int right){
    int k = putereDoiLowerbound(right - left + 1);

    return min(RMQ[k][left], RMQ[k][right - (1 << k) + 1]);
}
/////////////////////

int lca(int A, int B){
    if(firstEul[A] > firstEul[B]){
        swap(A, B);
    }

    return minimRMQ(firstEul[A], firstEul[B]);
}
/////////////////////

int NR;
int POS;
int VAL;
int A, B;
/////////////////////

void updateTree(int node, int left, int right){
    if(left == right){
        tree[NR][node] = VAL;
        return;
    }

    int mid = left + (right - left) / 2;

    if(POS <= mid){
        updateTree(node * 2, left, mid);
    }
    else {
        updateTree(node * 2 + 1, mid + 1, right);
    }

    tree[NR][node] = max(tree[NR][node * 2], tree[NR][node * 2 + 1]);
}
/////////////////////

int queryTree(int node, int left, int right){
    if(A <= left && right <= B){
        return tree[NR][node];
    }

    int mid = left + (right - left) / 2;

    int rez1 = -1, rez2 = -1;
    if(A <= mid){
        //A oricum e 1 mereu deci mereu se va intra in acest if
        rez1 = queryTree(node * 2, left, mid);
    }
    if(B >= mid + 1){
        rez2 = queryTree(node * 2 + 1, mid + 1, right);
    }

    return max(rez1, rez2);
}
/////////////////////

int maximPeLant(int JOS, int SUS){
    int REZ = -1;

    while(lant[JOS] != lant[SUS]){
        //printf("JOS = %d\n", JOS);

        //urc
        NR = lant[JOS];
        A = posLant[ tataLant[NR] ];
        B = posLant[ JOS ];

        /*
        printf("REZ = %d\n", REZ);
        printf("NR = %d\n", NR);
        printf("queryTree(1, 1, %d)\n", dimensiuneLant[NR]);
        */
        REZ = max( REZ, queryTree(1, 1, dimensiuneLant[NR]) );

        /*
        printf("REZ = %d\n", REZ);

        printf("JOS = %d\n", JOS);
        */
        JOS = tt[ tataLant[ lant[JOS] ] ];
        //printf("JOS = %d\n", JOS);
    }

    //printf("sfarsit While!\n");

    //acum au ajuns pe acelasi lant JOS si SUS
    NR = lant[JOS];
    A = posLant[ tataLant[NR] ];
    B = posLant[ JOS ];

    REZ = max( REZ, queryTree(1, 1, dimensiuneLant[NR]) );

    //printf("Sfarsit maximPeLant!\n");

    //printf("\n\n");
    return REZ;
}
/////////////////////


int rezultat(int X, int Y){
    int LCA = lca(X, Y);

    //printf("lca(%d, %d) = %d\n", X, Y, LCA);

    return max( maximPeLant(X, LCA), maximPeLant(Y, LCA) );
}
/////////////////////

int main()
{
    int N, M;
    fin >> N >> M;

    for(int i = 1; i <= N; i++){
        fin >> val[i];
    }

    for(int i = 1; i <= N - 1; i++){
        int x, y;
        fin >> x >> y;

        v[x].push_back(y);
        v[y].push_back(x);
    }

    tt[1] = 1;
    DFS(1, 1);
    buildPos(1, 1);
    computeRMQ();


    /*
    for(int i = 1; i <= N; i++){
        printf("lant[ %d ] = %d\n", i, lant[i]);
    }
    printf("\n\n");

    printf("Ajuns!\n");
    */



    for(int i = 1; i <= N; i++){
        NR = lant[i];
        POS = posLant[i];
        VAL = val[i];
        updateTree(1, 1, dimensiuneLant[NR]);
    }

    //printf("Ajuns!\n");

    for(int i = 1; i <= M; i++){
        //cout << "i = " << i << "\n";

        int tip, x, y;
        fin >> tip >> x >> y;

        if(tip == 0){
            NR = lant[x];
            POS = posLant[x];
            VAL = y;
            updateTree(1, 1, dimensiuneLant[NR]);
        }

        else {
            fout << rezultat(x, y) << "\n";
        }
    }

    return 0;
}