Cod sursa(job #3296628)

Utilizator iulia_morariuIuli Morariu iulia_morariu Data 14 mai 2025 19:49:33
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.63 kb
#include <algorithm>
#include <iostream>
#include <fstream>
#include <climits>
#include <vector>
#include <stack>
#include <cmath>
// #include <bits/stdc++.h>
#define in  fin
#define out fout

using namespace std;

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

struct nod{
    int val;   // ce valoare tine
    int lant;  // in ce lant este
    int idx;   // in reindexare (da este inspirata de solutia Emei)
    int dad;   // se explica din nume
    int sch;   // nr maxim de schimbari pana jos
    int nivel; // unde e nodul ca nivel in graf
};

nod v[100001];
vector<int> g[100001]; // adiancentele
int aint[4 * 100001];
int n;

vector<int> l; // l[i] = top-ul lantului i

void build_lanturi(int node){
    if(g[ node ].size() == 1 && g[node][0] == v[node].dad){
        // cout << node << " e leaf.\n";
        v[node].lant = l.size(); // se face lant nou pentru nodul meu
        l.push_back(node);
        v[node].sch = 0;
        return;
    }

    int maxi = -1, cntmax = 0, care_copil = 0;
    for(const int &cop : g[node]){
        if(cop == v[node].dad) continue;
        v[cop].dad = node;
        v[cop].nivel = v[node].nivel + 1;
        build_lanturi(cop);

        if(v[cop].sch > maxi){
            maxi = v[cop].sch;
            care_copil = cop;
            cntmax = 1;
        }else if(v[cop].sch == maxi) cntmax++;
    }

    // cout << "Am terminat cu " << node << '\n';
    // cout << "  -- > Continui lantul de la " << care_copil << '\n';
    
    v[node].lant = v[care_copil].lant;
    l[ v[node].lant ] = node;
    if(cntmax == 1) v[node].sch = maxi;
    else v[node].sch = maxi + 1;
}

// acuma trebe sa le reindexed
bool cmp(const int &a, const int &b){
    if(v[a].lant != v[b].lant) return v[a].lant < v[b].lant;
    else return v[a].nivel < v[b].nivel; // sa fie ala de sus mai in fata
}

vector<int> freaky_sort; // reindex

void reindexare(){
    for(int i = 1; i <= n; i++) freaky_sort.push_back(i);
    sort(freaky_sort.begin(), freaky_sort.end(), cmp);
    // cerr << "freak : ";
    // for(const int &x : freaky_sort) cerr << x << " ";
    // cerr << '\n';
    for(int i = 0; i < n; i++){
        v[ freaky_sort[i] ].idx = i + 1;
    }
}

// acuma trebe aint

void build(int l, int r, int p){
    if(l == r){
        aint[p] = v[ freaky_sort[l - 1] ].val;
        return;
    }

    int m = (l + r) / 2;
    build(l, m, p * 2);
    build(m + 1, r, p * 2 + 1);

    aint[p] = max(aint[p * 2], aint[p * 2 + 1]);
}

void update(int l, int r, int p, int poz, int val){
    if(l == r){
        aint[p] = val;
        // v[poz].val = val;
        return;
    }

    int m = (l + r) / 2;
    if(poz <= m) update(l, m, p * 2, poz, val);
    else update(m + 1, r, p * 2 + 1, poz, val);

    aint[p] = max(aint[p * 2], aint[p * 2 + 1]);
}

int query(int l, int r, int p, int l1, int r1){
    if(l1 <= l && r <= r1) return aint[p];

    int m = (l + r) / 2;
    int sol = 0;
    if(l1 <= m) sol = max(sol, query(l, m, p * 2, l1, r1));
    if(r1 > m) sol = max(sol, query(m + 1, r, p * 2 + 1, l1, r1));

    return sol;
}

/*
deci ce skibidi facem de aici este
- am a si b
- tot il aduc pe ala de pe lantul de mai jos mai sus pana is pe acelasi lant
- fac un query sigma pe aint la fiecare
*/

int query_freaky(int a, int b){ // query pentru alea reale, 2 noduri
    int sol = 0;
    while(v[a].lant != v[b].lant){
        int capA = l[ v[a].lant ];
        int capB = l[ v[b].lant ];

        // cout << "Sunt la a = " << a << " si b = " << b << '\n';
        // cout << "----> capa = " << capA << " capb = " << capB << '\n';

        if( v[ capA ].nivel < v[ capB ].nivel ){
            // osa fur ideea Emei si atunci a e totimpul mai jos
            swap(a, b);
            swap(capA, capB);
        }

        sol = max(sol, query(1, n, 1, v[capA].idx, v[a].idx));
        // cout << "sol = " << sol << '\n';
        a = v[ capA ].dad;
    }
    // cout << "a = " << a << " b = " << b << '\n';
    // si ultimul lant
    if(v[a].nivel < v[b].nivel) sol = max(sol, query(1, n, 1, v[a].idx, v[b].idx));
    else sol = max(sol, query(1, n, 1, v[b].idx, v[a].idx));
    
    // cout << "sol = " << sol << '\n';
    return sol;
}

signed main(){
    ios_base::sync_with_stdio(false);
    in.tie(NULL);

    int q; in >> n >> q;
    for(int i = 1; i <= n; i++) in >> v[i].val;
    for(int i = 0; i < n - 1; i++){
        int a, b; in >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    v[1].dad = -1;
    v[1].nivel = 0;
    build_lanturi(1);
    reindexare();
    build(1, n, 1);

    for(int _i = 0; _i < q; _i++){
        int t, a, b; in >> t >> a >> b;
        if(t == 0) update(1, n, 1, v[a].idx, b);
        else out << query_freaky(a, b) << '\n';
    }

    return 0;
}