Cod sursa(job #2832490)

Utilizator crismariuCrismariu Codrin crismariu Data 13 ianuarie 2022 20:19:26
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.22 kb
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#pragma GCC optimize("O3")
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define pb push_back
#define printArr(v, n) for(int i = 0; i < n; i++) cout << v[i] << ' ';
#define readArr(v, n) for(int i = 0; i < n; i++) cin >> v[i];
#define FASTIO cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);
#define FILES freopen("heavypath.in", "r", stdin); freopen("heavypath.out", "w", stdout);
using namespace std;
using namespace __gnu_pbds;

template<typename T>
using ordered_set = tree<T,null_type,less<T>, rb_tree_tag,tree_order_statistics_node_update>;

const int NMAX = 1e5 + 5;

struct seg_tree {
    int Size;
    int * idk;

    seg_tree(vector <int> & v) {

        Size = v.size();
        idk = new int[Size << 2];
        init(1, Size, 1, v);

    }

    int init(int l, int r, int ind, vector <int> & v) {
        if(l == r) return idk[ind] = v[l - 1];

        int mid = (l + r) / 2;
        idk[ind] = max( init(l, mid, ind << 1, v),
                        init(mid + 1, r, (ind << 1) + 1, v) );

        return idk[ind];
    }

    int query(int L, int R, int ind, int l, int r) {
        if(l > R || L > r) return INT_MIN;
        if(l >= L && r <= R) return idk[ind];

        int mid = (l + r) / 2;
        return max( query(L, R, ind << 1, l, mid),
                    query(L, R, (ind << 1) + 1, mid + 1, r) );
    }

    void update(int pos, int val, int ind, int l, int r) {
        if(l == r)  {
            idk[ind] = val;
            return;
        }

        int mid = (l + r) / 2;
        if(pos <= mid)
            update(pos, val, ind << 1, l, mid);
        else
            update(pos, val, (ind << 1) + 1, mid + 1, r);

        idk[ind] = max(idk[ind << 1], idk[(ind << 1) + 1]);
    }
};

vector <int> path[NMAX], adj[NMAX];
seg_tree * Seg[NMAX];
int value[NMAX], head[NMAX], depth[NMAX],
    sub_tree[NMAX], parent[NMAX], pathOf[NMAX],
    pos[NMAX];

int init(int node, int dad = 0) {
    parent[node] = dad;

    for(int kid : adj[node])
        if(kid != dad)
            sub_tree[node] += init(kid, node) + 1;

    return sub_tree[node];
}

int cnt = 1;
void decompose(int node, int component, bool heavy = 0, int height = 0) {
    path[component].pb(value[node]);
    pathOf[node] = component;
    pos[node] = path[component].size() - 1;
    depth[node] = height;
    if(!heavy)
        head[node] = node;
    else
        head[node] = head[parent[node]];

    int mx = 0;
    for(int kid : adj[node])
        if(kid != parent[node])
            mx = max(mx, sub_tree[kid]);

    for(int kid : adj[node])
        if(kid != parent[node]) {
            if(sub_tree[kid] == mx)
                decompose(kid, component, 1, height), mx = INT_MAX;
            else
                decompose(kid, ++cnt, 0, height + 1);
        }
}

int query(int x, int y) {
    int mx = INT_MIN;
    for(; head[x] != head[y]; x = parent[head[x]]) {
        if(depth[x] < depth[y])
            swap(x, y);

        int P = pathOf[x];
        mx = max(mx, Seg[P]->query(pos[head[x]] + 1, pos[x] + 1,
                                   1, 1, path[P].size()));
    }

    int l = min(pos[x], pos[y]);
    int r = max(pos[x], pos[y]);
    int P = pathOf[x];

    return max(mx, Seg[P]->query(l + 1, r + 1, 1, 1, path[P].size()));
}

void update(int node, int val) {
    int P = pathOf[node];

    Seg[P]->update(pos[node] + 1, val, 1, 1, path[P].size());
}

signed main() {
    FASTIO;
    #ifndef ONLINE_JUDGE
        FILES;
    #endif // ONLINE_JUDGE

    int n, q; cin >> n >> q;

    for(int i = 1; i <= n; i++)
        cin >> value[i];

    for(int i = 0; i < n - 1; i++) {
        int x, y;
        cin >> x >> y;

        adj[x].pb(y);
        adj[y].pb(x);
    }

    init(1);
    decompose(1, cnt, 0, 0);

    for(int i = 1; i <= cnt; i++)
        Seg[i] = new seg_tree(path[i]);

    while(q--) {

        int t, x, y;
        cin >> t >> x >> y;

        if(t == 0) {

            update(x, y);

        } else {

            cout << query(x, y) << '\n';

        }

    }
    return 0;
}