Cod sursa(job #2762979)

Utilizator NeacsuMihaiNeacsu Mihai NeacsuMihai Data 10 iulie 2021 18:40:41
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.27 kb
#include <iostream>
#include <fstream>
#include <vector>

#define NMAX 100000 //o suta de mii

using namespace std;

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

int N, M;
int REZ;
int nrLanturi;

int tt[NMAX + 1];
int val[NMAX + 1];
vector <int> v[NMAX + 1];
int lant[NMAX + 1];
int posLant[NMAX + 1];
int tataLant[NMAX + 1];
int dimensiuneLant[NMAX + 1];
int depth[NMAX + 1];

int **tree;

void citire(){
    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);
    }
}


int DFSfirst(int node, int tata){
    int smNode = 1;
    tt[node] = tata;
    depth[node] = depth[tata] + 1;

    int MX = -1;
    int vecMx;

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

        if(vec != tata){
            int smVec = DFSfirst(vec, node);

            if(smVec > MX){
                MX = smVec;
                vecMx = vec;
            }

            smNode += smVec;
        }
    }

    if(MX == -1){
        //frunza
        nrLanturi++;
        lant[node] = nrLanturi;
        dimensiuneLant[nrLanturi] = 1;
        tataLant[nrLanturi] = node;
    }
    else {
        lant[node] = lant[vecMx];
        dimensiuneLant[ lant[node] ]++;
        tataLant[ lant[node] ] = node;
    }

    return smNode;
}

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

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

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

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

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

    int rez1 = -1, rez2 = -1;
    if(A <= mid){
        rez1 = queryTree(tree, node * 2, left, mid, A, B);
    }
    if(B >= mid + 1){
        rez2 = queryTree(tree, node * 2 + 1, mid + 1, right, A, B);
    }

    return max(rez1, rez2);
}

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

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

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

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


void urcareLant(int &node){
    int NR = lant[node];
    int nd = 1;
    int left = 1;
    int right = dimensiuneLant[NR];
    int A = 1;
    int B = posLant[node];

    REZ = max(REZ, queryTree(tree[NR], nd, left, right, A, B));

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

inline int comparareLant(int X, int Y){
    //returneaza 1 daca X e mai sus, 0 daca Y e mai sus
    return depth[ tataLant[ lant[X] ] ] < depth[ tataLant[ lant[Y] ] ];
}

int query(int X, int Y){
    //X mereu trebuie sa fie in lantul mai de sus
    REZ = -1;

    if( !comparareLant(X, Y) ){ //adica daca lantul lui Y este mai sus decat lantul lui X
        swap(X, Y);
    }

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

        //printf("Urc pe lant %d\n", Y);
        urcareLant(Y);
        //printf("Am urcat pe lant %d\n", Y);

        if( !comparareLant(X, Y) ){
            swap(X, Y);
        }
    }

    if(posLant[X] > posLant[Y]){
        swap(X, Y);
    }
    REZ = max(REZ, queryTree(tree[ lant[X] ], 1, 1, dimensiuneLant[ lant[X] ], posLant[X], posLant[Y]));


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

inline void buildTree(){
    //aloc memorie
    tree = (int **) malloc( (nrLanturi + 1) * sizeof(int *) );
    for(int i = 1; i <= nrLanturi; i++){
        tree[i] = (int *) malloc( (4 * dimensiuneLant[i] + 1) * sizeof(int) );
    }

    //fac build propriu-zis
    for(int i = 1; i <= N; i++){
        updateTree(tree[ lant[i] ], 1, 1, dimensiuneLant[ lant[i] ], posLant[i], val[i]);
    }
}

int main()
{
    citire();
    DFSfirst(1, 1);
    DFSsecond(1, 1);
    buildTree();

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

    for(int i = 1; i <= nrLanturi; i++){
        printf("Lantul %d are dimensiunea %d\n", i, dimensiuneLant[i]);
    }
    printf("\n");

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

    for(int i = 1; i <= M; i++){
        //printf("Inceput %d!\n", i);

        int tip, X, Y;
        fin >> tip >> X >> Y;

        if(tip == 0){
            //update
            updateTree(tree[ lant[X] ], 1, 1, dimensiuneLant[ lant[X] ], posLant[X], Y);
        }
        else {
            fout << query(X, Y) << "\n";
        }

        //printf("Sfarsit %d!\n", i);

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

    return 0;
}