Cod sursa(job #2803890)

Utilizator OvidRata Ovidiu Ovid Data 20 noiembrie 2021 16:42:25
Problema Heavy Path Decomposition Scor 10
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.91 kb
#include<bits/stdc++.h>
using namespace std;
#define INIT  ios_base :: sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
#define mp make_pair
#define pb push_back
#define ft first
#define sc second
#define ll long long
#define pii pair<int, int>
#define count_bits __builtin_popcount

inline char get_ (){
    const int oo=1000005;
    static char buf[oo], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, oo, stdin), p1 == p2) ? EOF : *p1 ++;
}
int read_ () {
    char c = get_();
    int sum = 0;
    while(!(c >= '0' && c <= '9')) c = get_();
    while(c >= '0' && c <= '9') sum = sum * 10 + (c - '0'), c = get_();
    return sum;
}



int n, m, v[100010];
vector<int> g[100010];




int pos[100010];
int hd[100010];
int par[100010];

int val[100010];

int sz[100010];

bool vr[100010];

//graph traversals and perequisites
void dfs_sz(int s){
vr[s]=true;
int res=1;
for(auto u:g[s]){
    if(!vr[u]){
        par[u]=s;
        dfs_sz(u);
        res+=sz[u];
    }
}
vr[s]=false;
sz[s]=res;
}

int tmp=0;

int tmp1=0, ent[100010], ex[100010];

void build_path(int s, int h){
    tmp++;
    tmp1++;
    ent[s]=tmp1;
    pos[s]=tmp;
    val[pos[s] ]=v[s];

    hd[s]=h;
    pii nxt={0, 0};
    for(auto u:g[s]){
        if(u!=par[s]){nxt=max(nxt, {sz[u], u});}
    }
    if(nxt!=mp(0, 0) ){
        build_path(nxt.sc, h);
    }
    for(auto u:g[s]){
        if( (u!=par[s]) && (u!=nxt.sc) ){
            build_path(u, u);
        }
    }
    tmp1++;
    ex[s]=tmp1;
    return;
}


//segtree
int tree[400010];

void build_seg(int v, int l, int r){
if(l==r){
    tree[v]=val[l];
    return;
}
int m=(l+r)>>1ll;
build_seg(v*2, l, m); build_seg(2*v+1, m+1, r);
tree[v]=max(tree[v*2], tree[v*2+1]);
}




int query(int v, int tl, int tr, int l, int r){

if(l>r){
    return 0;
}

if( (tl==l) && (tr==r) ){
    return tree[v];
}

int m=(tl+tr)>>1ll;
return max(  query(v*2, tl, m, l, min(r, m)), query(v*2+1, m+1, tr, max(l, m+1), r ) );
}


void update(int v, int l, int r, int x, int y){

if(l==r){
    tree[v]=val[x]=y;
    return;
}
int m=(l+r)>>1ll;
if(x<=m){
    update(v*2, l, m, x, y);
}
else{
    update(2*v+1, m+1, r, x, y);
}
tree[v]=max(tree[v*2], tree[v*2+1] );
}



//LCA
int anc[100010][20];

void build_lca(){

for(int i=1; i<=n; i++){
    anc[i][0]=par[i];
}
for(int j=1; j<=18; j++){
    for(int i=1; i<=n; i++){
        anc[i][j]=anc[anc[i][j-1] ][j-1];
    }
}

}

bool is_anc(int u, int v){
return ent[u]<ent[v] && ex[u]>ex[v];
}

int find_lca(int u, int v){

if(is_anc(u, v)){
    return u;
}
if(is_anc(v, u) ){
    return v;
}

int ac=u;
for(int j=18; j>=0; j--){
    if( (anc[ac][j]!=0) && ( !is_anc(anc[ac][j], v ) ) ){
        ac=anc[ac][j];
    }
}
return anc[ac ][0];
}




//get_max answers for a chain from the vertex to an ancestor
//v is anc
int get_max(int u, int v){

if(hd[u]==hd[v]){
    return query(1, 1, n, pos[v], pos[u]);
}

return max( query(1, 1, n, pos[hd[u] ], pos[u]), get_max(par[hd[u] ], v)  );

}




ifstream fin("heavypath.in"); ofstream fout("heavypath.out");
#define cin fin
#define cout fout


int32_t main(){
INIT
cin>>n>>m;
for(int i=1; i<=n; i++){
    cin>>v[i];
}
for(int i=1; i<n; i++){
    int a,b;
    cin>>a>>b;
    g[a].pb(b);
    g[b].pb(a);
}

dfs_sz(1);
build_path(1, 1);
build_seg(1, 1, n);
build_lca();

/*
for(int i=1; i<=n; i++){
    cout<<hd[i]<<" ";
}
cout<<"\n"<<flush;
*/

for(int i=1; i<=m; i++){
    int t, x, y;
    cin>>t>>x>>y;
    if(t==0){
        update(1, 1, n, pos[x], y);
    }
    else{
        int m1=0, m2=0;
        int lca=find_lca(x, y);
        //cout<<lca<<"\n"<<flush;
        m1=get_max(x, lca), m2=get_max(y, lca);
        cout<<max(m1, m2)<<"\n";
    }

}



return 0;
}