Cod sursa(job #2986408)

Utilizator BlueLuca888Girbovan Robert Luca BlueLuca888 Data 28 februarie 2023 16:26:02
Problema Heavy Path Decomposition Scor 0
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.89 kb
#include <bits/stdc++.h>

using namespace std;

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

const int LIM = 100'000;
int n, q, t, x, y, z;
int v[LIM + 5], w[LIM + 5], index_norm[LIM + 5], normalizare[LIM + 5];
vector <int> edge[LIM + 5];

int subarbore[LIM + 5], parent[LIM + 5];
inline void calc_subarbore(int crt, int prv){
    parent[crt] = prv;
    subarbore[crt] = 1;
    for(auto nxt : edge[crt])
        if(nxt != prv){
            calc_subarbore(nxt, crt);
            subarbore[crt] += subarbore[nxt];
        }
}

inline void continue_lant(int crt, int prv, int lantindex);

int lantcnt, freq_lant[LIM + 5], lft_lant[LIM + 5], rgt_lant[LIM + 5];
vector <int> lant[LIM + 5];
inline void start_lant(int crt, int prv){
    lantcnt++;
    lant[lantcnt].push_back(crt);

    int max_val=0, max_son=-1;
    for(auto nxt : edge[crt])
        if(nxt != prv){
            if(max_val < subarbore[nxt]){
                max_val = subarbore[nxt];
                max_son = nxt;
            }
        }

    int lantcrt = lantcnt;
    if(max_son != -1)
        for(auto nxt : edge[crt])
            if(nxt != prv){
                if(max_son == nxt)
                    continue_lant(nxt, crt, lantcrt);
                else
                    start_lant(nxt, crt);
            }
}

inline void continue_lant(int crt, int prv, int lantindex){
    lant[lantindex].push_back(crt);

    int max_val=0, max_son=-1;
    for(auto nxt : edge[crt])
        if(nxt != prv){
            if(max_val < subarbore[nxt]){
                max_val = subarbore[nxt];
                max_son = nxt;
            }
        }

    if(max_son != -1)
        for(auto nxt : edge[crt])
            if(nxt != prv){
                if(max_son == nxt)
                    continue_lant(nxt, crt, lantindex);
                else
                    start_lant(nxt, crt);
            }
}

struct SEGTREE{
    int aint[4 * LIM + 5];

    inline void build(int nod=1, int st=1, int dr=n){
        if(st == dr){
            aint[nod] = w[st];
        }else{
            int md = ((st + dr) >> 1);
            build(2*nod  , st  , md);
            build(2*nod+1, md+1, dr);
            aint[nod] = max(aint[2*nod], aint[2*nod+1]);
        }
    }

    inline void update(int poz, int val, int nod=1, int st=1, int dr=n){
        if(st == dr){
            aint[nod] = val;
        }else{
            int md = ((st + dr) >> 1);
            if(poz <= md) update(val, poz, 2*nod  , st  , md);
            if(poz >  md) update(val, poz, 2*nod+1, md+1, dr);
            aint[nod] = max(aint[2*nod], aint[2*nod+1]);
        }
    }

    inline int query(int qst, int qdr, int nod=1, int st=1, int dr=n){
        if(qst <= st && dr <= qdr){
            return aint[nod];
        }else{
            int md = ((st + dr) >> 1), answer = 0;
            if(qst <= md) answer = max(answer, query(qst, qdr, 2*nod  , st  , md));
            if(qdr >  md) answer = max(answer, query(qst, qdr, 2*nod+1, md+1, dr));
            return answer;
        }
    }
} tree;

int ecnt, euler[2 * LIM + 5], nivel[LIM + 5], level[LIM + 5], first[LIM + 5];
inline void calc_euler(int crt, int prv){
    level[crt] = level[prv] + 1;

    euler[++ecnt] = crt;
    nivel[ecnt] = level[crt];
    first[crt] = ecnt;

    for(auto nxt : edge[crt])
        if(nxt != prv){
            calc_euler(nxt, crt);
            euler[++ecnt] = crt;
            nivel[ecnt] = level[crt];
        }
}

int rmq[18][2 * LIM + 5];
inline void calc_rmq(){
    for(int j=1; j<=ecnt; j++)
        rmq[0][j] = j;
    for(int i=1; (1 << i)<=ecnt; i++)
        for(int j=1, jj; (jj = j + (1 << (i-1)))<=ecnt; j++)
            if(nivel[ rmq[i-1][j] ] < nivel[ rmq[i-1][jj] ])
                rmq[i][j] = rmq[i-1][j];
            else
                rmq[i][j] = rmq[i-1][jj];
}

inline int lca(int nod1, int nod2){
    nod1 = first[nod1];
    nod2 = first[nod2];
    if(nod1 > nod2)
        swap(nod1, nod2);

    int lg2 = (int)log2(nod2 - nod1 + 1);
    nod2 -= (1 << lg2) - 1;
    if(nivel[ rmq[lg2][nod1] ] < nivel[ rmq[lg2][nod2] ])
        return euler[ rmq[lg2][nod1] ];
    else
        return euler[ rmq[lg2][nod2] ];
}

inline int query_lant(int nod, int target){
    if(freq_lant[nod] == freq_lant[target]){ ///sunt pe acelasi lant
        return tree.query(index_norm[target], index_norm[nod]);
    }else{
        int answer = tree.query(index_norm[ lant[freq_lant[nod]][0] ], index_norm[nod]);
        answer = max(answer, query_lant(parent[ lant[freq_lant[nod]][0] ], target));
        return answer;
    }
}

int main (){
    ios_base::sync_with_stdio(false);
    fin.tie(nullptr), fout.tie(nullptr);

    fin>>n>>q;

    for(int i=1; i<=n; i++)
        fin>>v[i];

    for(int i=1, u, v; i < n; i++){
        fin>>u>>v;
        edge[u].push_back(v);
        edge[v].push_back(u);
    }

    calc_subarbore(1, 0);
    start_lant(1, 0);

    int cnt = 0;
    for(int i=1; i<=lantcnt; i++){
        lft_lant[i] = cnt + 1;
        for(auto nod : lant[i]){
            freq_lant[nod] = i;
            normalizare[++cnt] = nod;
            index_norm[nod] = cnt;
            w[cnt] = v[nod];
        }
        rgt_lant[i] = cnt;
    }

    /*for(int i=1; i<=n; i++)
        fout<<normalizare[i]<<" ";
    fout<<"\n";
    for(int i=1; i<=n; i++)
        fout<<w[i]<<" ";


    for(int i=1; i<=lantcnt; i++){
        fout<<"\n\n";
        for(auto nod : lant[i])
            fout<<nod<<" ";
        fout<<"\n"<<lft_lant[i]<<" "<<rgt_lant[i];
    }
    fout<<"\n\n";*/

    calc_euler(1, 0);
    calc_rmq();

    tree.build();
    while(q--){
        fin>>t>>x>>y;
        if(t == 0){ ///update
            tree.update(x, y);
        }else{ ///query
            z = lca(x, y);
            fout<<max(query_lant(x, z), query_lant(y, z))<<"\n";
        }
    }
    return 0;
}