Cod sursa(job #3308122)

Utilizator Iustin_Mircea2010Iustin Mircea Iustin_Mircea2010 Data 23 august 2025 13:37:23
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.16 kb
#include <bits/stdc++.h>
#pragma GCC optimize("O3","Ofast")
#pragma GCC target("avx2","bmi","popcnt","lzcnt","bmi2")
using namespace std;

int v[100005], par[100005], arb[100005], level[100005], cnt = 0, curr_comp = 0;
int comp[100005]; //din ce lant heavy face parte
int leader[100005]; //parintele fiecarui lant heavy
int order[100005]; // ce index are DUPA decomp
int reale[100005]; //care nod(din notatia initiala, input) ii corespunde indexului i?
vector<int> adj[100005];

void inradacinez(int u, int p = 0){
    par[u] = p;
    level[u] = level[p] + 1;
    int curr = 1;
    for(int nod : adj[u]){
        if(nod == p) continue;
        inradacinez(nod, u);
        curr += arb[nod];
    }
    arb[u] = curr;
}

void dfs(int nod, bool heavy = 0){
    order[nod] = ++cnt;
    reale[cnt] = nod;
    if(heavy == 0){
        comp[nod] = ++curr_comp;
        leader[curr_comp] = nod;
    }
    else
        comp[nod] = comp[par[nod]];
    int maxarb = -1, which = 0;
    for(int copil : adj[nod]){
        if(copil == par[nod]) continue;
        if(arb[copil] > maxarb){
            which = copil;
            maxarb = arb[copil];
        }
    }
    if(which != 0)
        dfs(which, 1);
    for(int copil : adj[nod]){
        if(copil == par[nod] || copil == which) continue;
        dfs(copil, 0);
    }
}

struct segmentTree{
    int aint[400005];

    void build(int i, int l, int r){
        if(l == r){
            aint[i] = v[reale[l]]; //actionam asupra celui cu ord[] = l, dar vrem valoarea lui, nu v[l]
            return;
        }
        int mid = (l + r) >> 1;
        build(2 * i, l, mid);
        build(2 * i + 1, mid + 1, r);
        aint[i] = max(aint[2 * i], aint[2 * i + 1]);
    }

    void update(int i, int l, int r, int poz, int x){
        if(l == r && l == poz){
            aint[i] = x;
            return;
        }
        if(l > poz || r < poz) return;
        int mid = (l + r) >> 1;
        update(2 * i, l, mid, poz, x);
        update(2 * i + 1, mid + 1, r, poz, x);
        aint[i] = max(aint[2 * i], aint[2 * i + 1]);
    }

    int query(int i, int curl, int curr, int l, int r){
        if(curl > r || curr < l) return 0;
        if(l <= curl && curr <= r) return aint[i];
        int mid = (curl + curr) >> 1;
        return max(query(2 * i, curl, mid, l, r),
                   query(2 * i + 1, mid + 1, curr, l, r));
    }

}Tree;

int main()
{
    //ios_base::sync_with_stdio(false);
    //cin.tie(nullptr);
    //cout.tie(nullptr);

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

    int n, q;
    cin >> n >> q;
    for(int i = 1; i <= n; i++){
        cin >> v[i];
    }
    int a, b;
    for(int i = 1; i < n; i++){
        cin >> a >> b;
        adj[a].push_back(b);
        adj[b].push_back(a);
    }
    //o sa fac il inradacinez in 1 si o sa retin parintii in par, also calculez marimea subarborelui in arb si depthul
    inradacinez(1);

    //acum fac decompostion-ul, imi retin care nod e la rand, din ce lant face parte si parintele lantului
    dfs(1);

    //fac aintul
    Tree.build(1, 1, n);

    //in sfarsit, queryuri
    int type, node, x, ans;
    while(q--){
        cin >> type;
        if(type == 1){
            cin >> node >> x;
            Tree.update(1, 1, n, order[node], x);
        }
        else{
            ans = -1;
            cin >> a >> b;
            for(; leader[comp[a]] != leader[comp[b]]; b = par[leader[comp[b]]]){ // "urc" b tot timpul(totusi le dau swap uneori), cat timp nu le am ridicat la acelasi lant
                if(level[leader[comp[a]]] > level[leader[comp[b]]]) //daca lantul lui a este mai jos decat lantul lui b, le schimb
                    swap(a, b);
                ans = max(ans, Tree.query(1, 1, n, order[leader[comp[b]]], order[b])); //mai intai il pun pe cel cu nivel mai sus din arbore, pentru ca are order mai mic
            }
            //acum a si b sunt pe acelasi lant, mai pun doar ce a ramas
            if(level[a] > level[b]) swap(a, b);
            ans = max(ans, Tree.query(1, 1, n, order[a], order[b]));
            cout << ans << '\n';
        }
    }
    return 0;
}