Cod sursa(job #3156912)

Utilizator Summer05Cocut Alexandru Summer05 Data 13 octombrie 2023 17:42:39
Problema Heavy Path Decomposition Scor 80
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 11.16 kb
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <climits>
#include <iomanip>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <iterator>
#include <vector>
#include <algorithm>
#include <numeric>
#include <queue>
#include <stack>
#include <bitset>
#include <functional>
#include <utility>
#include <cmath>
#include <string>
#include <deque>
#include <array>
#include <tuple>
#include <cstring>
#include <ctime>
#include <random>
#include <chrono>
///#include <windows.h>

#pragma GCC optimize("fast-math")

#define ll int
#define ld long double
#define pll pair<ll, ll>
#define psi pair<short int, short int>
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
#define all(x) (x).begin() + 1, (x).end()
#define all0(x) (x).begin(), (x).end()
#define allrev(x) (x).rbegin(), (x).rend() - 1
#define allrev0(x) (x).rbegin(), (x).rend()
#define println(thing) cout << thing << '\n'
#define yes println("YES")
#define no println("NO")
#define maybe println("MAYBE")
#define mda println("/////////////////")
#define msb(x) ((x) == 0 ? 0 : (1 << (64 - __builtin_clzll(x) - 1)))
#define lsb(x) ((x) & (-x))

using namespace std;

mt19937_64 rng(chrono :: steady_clock :: now().time_since_epoch().count());

const size_t fixed_random = rng();

clock_t start_time = clock(), end_time;

ll random_seed(ll modulo) {
    return rng() % modulo;
}

template <typename T>
inline void hash_combine(size_t& seed, const T& value) {
    seed ^= hash<T>{}(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

struct pair_hash {
    template <typename T1, typename T2>
    size_t operator () (const pair<T1, T2>& p) const {
        size_t seed = fixed_random;

        hash_combine(seed, p.first);
        hash_combine(seed, p.second);

        return seed;
    }
};

struct normal_hash {
    template <typename T>
    size_t operator () (const T& p) const {
        size_t seed = fixed_random;

        hash_combine(seed, p);

        return seed;
    };
};

template <typename unordered_Map>
void optimize_map(unordered_Map& M) {
    M.reserve(1024);
    M.max_load_factor(0.5);
}

template <typename T1, typename T2>
istream& operator >> (istream& in, pair<T1, T2>& p) {
    in >> p.first >> p.second;
    return in;
}

template <typename T1, typename T2>
ostream& operator << (ostream& out, pair<T1, T2>& p) {
    out << p.first << ' ' << p.second;
    return out;
}

/// for bitset bits
template <typename T1, typename T2> T1 operator ^= (T1 t1, T2 t2) {t1 = t1 ^ t2; return t1;}
template <typename T1, typename T2> T1 operator |= (T1 t1, T2 t2) {t1 = t1 | t2; return t1;}
template <typename T1, typename T2> T1 operator &= (T1 t1, T2 t2) {t1 = t1 & t2; return t1;}

const ll NMX = (ll) 1e5 + 1;
const ll MOD = (ll) 1e9 + 7;
const ll INF = (ll) 1e17;

ll binExp(ll base, ll exp) {
    ll P = 1;
    for (ll bit = 1; bit <= exp; bit <<= 1) {
        if (exp & bit)
            P = (P * base) % MOD;
        base = (base * base) % MOD;
    }
    return P;
}

inline ll modInv(ll x) {
    return binExp(x, MOD - 2);
}

ll test_case = 0;

const ll LOG = log2(NMX);

ll a[NMX], pv[NMX], jump[NMX][LOG + 1];
ll time_in[NMX], time_out[NMX], subtree_size[NMX];
ll top_chain[NMX], heavy_son[NMX], label[NMX], to_build[NMX];

vector<ll> g[NMX];

class maxSegTree {
public:
    vector<ll> tree;
    ll len;
///public:
    maxSegTree(ll _len) : len(_len), tree(4 * _len + 1, 0) {}
    void build(ll tl, ll tr, ll v) {
        if (tl == tr) {
            tree[v] = to_build[tl];
            return;
        }
        ll tm = ((tl + tr) >> 1);
        build(tl, tm, 2 * v);
        build(tm + 1, tr, 2 * v + 1);
        tree[v] = max(tree[2 * v], tree[2 * v + 1]);
    }
    void query(ll l, ll r, ll tl, ll tr, ll v, ll &mx) {
        if (l <= tl && tr <= r) {
            mx = max(mx, tree[v]);
            return;
        }
        ll tm = ((tl + tr) >> 1);
        if (l <= tm) {
            query(l, r, tl, tm, 2 * v, mx);
        }
        if (r > tm) {
            query(l, r, tm + 1, tr, 2 * v + 1, mx);
        }
        return;
    }
    void update(ll pos, ll val, ll tl, ll tr, ll v) {
        if (tl == tr) {
            tree[v] = val;
            return;
        }
        ll tm = ((tl + tr) >> 1);
        if (pos <= tm) {
            update(pos, val, tl, tm, 2 * v);
        }
        if (pos > tm) {
            update(pos, val, tm + 1, tr, 2 * v + 1);
        }
        tree[v] = max(tree[2 * v], tree[2 * v + 1]);
        return;
    }
};

void solve(ll testcase)
{
    ll n, q;
    cin >> n >> q;

    for (ll i = 1; i <= n; i++) {
        cin >> a[i];
    }

    for (ll i = 1, v, u; i <= n - 1; i++) {
        cin >> v >> u;
        g[v].push_back(u);
        g[u].push_back(v);
    }

    function<void(ll, ll)> find_parents = [&](ll v, ll par) {
        for (ll u : g[v]) {
            if (u != par) {
                pv[u] = v;
                find_parents(u, v);
            }
        }
        return;
    };

    find_parents(1, -1);

    for (ll i = 1; i <= n; i++) {
        jump[i][0] = pv[i];
    }

    for (ll j = 1; j <= LOG; j++) {
        for (ll i = 1; i <= n; i++) {
            jump[i][j] = jump[jump[i][j - 1]][j - 1];
        }
    }

    time_out[0] = INT_MAX;

    ll time = 0;

    function<void(ll, ll)> find_time = [&](ll v, ll par) {
        time_in[v] = ++time;
        for (ll u : g[v]) {
            if (u != par) {
                find_time(u, v);
            }
        }
        time_out[v] = ++time;
    };

    function<bool(ll, ll)> is_ancestor = [&](ll v, ll u) {
        return time_in[u] <= time_in[v] && time_out[u] >= time_out[v];
    };

    function<ll(ll, ll)> LCA = [&](ll v, ll u) {
        if (is_ancestor(v, u)) {
            return u;
        }
        if (is_ancestor(u, v)) {
            return v;
        }
        for (ll j = LOG; j >= 0; j--) {
            if (!is_ancestor(u, jump[v][j])) {
                v = jump[v][j];
            }
        }
        return jump[v][0];
    };

    find_time(1, -1);

    function<ll(ll, ll)> find_subtree_sizes = [&](ll v, ll par) {
        subtree_size[v] = 1;
        for (ll u : g[v]) {
            if (u != par) {
                subtree_size[v] += find_subtree_sizes(u, v);
            }
        }
        return subtree_size[v];
    };

    find_subtree_sizes(1, -1);

    function<void(ll, ll)> find_heavy_sons = [&](ll v, ll par) {
        ll heaviest_subtree = 0;
        for (ll u : g[v]) {
            if (u != par) {
                heaviest_subtree = max(heaviest_subtree, subtree_size[u]);
                find_heavy_sons(u, v);
            }
        }
        if (!heaviest_subtree) {
            return;
        }
        for (ll u : g[v]) {
            if (u != par) {
                if (subtree_size[u] == heaviest_subtree) {
                    heavy_son[v] = u;
                    break;
                }
            }
        }
    };

    find_heavy_sons(1, -1);

    ll label_counter = 0;

    function<void(ll, ll)> label_dfs = [&](ll v, ll par) {
        label[v] = ++label_counter;
        if (heavy_son[v]) {
            label_dfs(heavy_son[v], v);
        }
        for (ll u : g[v]) {
            if (u != par && u != heavy_son[v]) {
                label_dfs(u, v);
            }
        }
    };

    label_dfs(1, -1);

    function<void(ll, ll)> find_top_chains = [&](ll v, ll par) {
        if (heavy_son[par] == v) {
            top_chain[v] = top_chain[par];
        }
        else if (heavy_son[v]) {
            top_chain[v] = v;
        }
        for (ll u : g[v]) {
            if (u != par) {
                find_top_chains(u, v);
            }
        }
        return;
    };

    find_top_chains(1, -1);

    maxSegTree heavy_chains(n);

    function<void(ll, ll)> build_heavy_chains = [&](ll v, ll par) {
        if (!heavy_son[v] && heavy_son[par] == v) {
            ll top = label[top_chain[v]];
            ll bottom = label[v];

            ll vertex = top_chain[v];
            while (heavy_son[vertex]) {
                to_build[label[vertex]] = a[vertex];
                vertex = heavy_son[vertex];
            }
            to_build[label[vertex]] = a[vertex];
        }
        for (ll u : g[v]) {
            if (u != par) {
                build_heavy_chains(u, v);
            }
        }
        return;
    };

    build_heavy_chains(1, -1);

    heavy_chains.build(1, n, 1);

    for (ll qq = 1, op, x, y; qq <= q; qq++) {
        cin >> op >> x >> y;

        if (op == 0) { /// update a[x] to y
            if (heavy_son[x] || heavy_son[pv[x]] == x) {
                heavy_chains.update(label[x], y, 1, n, 1);
            }
            else {
                a[x] = y;
            }
        }
        else if (op == 1) { /// query from x to LCA(x, y) and from y to LCA(x, y)
            ll mx = INT_MIN, ancestor = LCA(x, y);

            while (x != pv[ancestor]) {
                if (heavy_son[x] || heavy_son[pv[x]] == x) {
                    if (is_ancestor(top_chain[x], ancestor)) {
                        ll top = label[top_chain[x]];
                        ll bottom = label[x];

                        heavy_chains.query(top, bottom, 1, n, 1, mx);

                        x = pv[top_chain[x]];
                    }
                    else {
                        ll top = label[ancestor];
                        ll bottom = label[x];

                        heavy_chains.query(top, bottom, 1, n, 1, mx);

                        x = pv[ancestor];
                    }
                }
                else {
                    mx = max(mx, a[x]);

                    x = pv[x];
                }
            }

            while (y != pv[ancestor]) {
                if (heavy_son[y] || heavy_son[pv[y]] == y) {
                    if (is_ancestor(top_chain[y], ancestor)) {
                        ll top = label[top_chain[y]];
                        ll bottom = label[y];

                        heavy_chains.query(top, bottom, 1, n, 1, mx);

                        y = pv[top_chain[y]];
                    }
                    else {
                        ll top = label[ancestor];
                        ll bottom = label[y];

                        heavy_chains.query(top, bottom, 1, n, 1, mx);

                        y = pv[ancestor];
                    }
                }
                else {
                    mx = max(mx, a[y]);

                    y = pv[y];
                }
            }

            cout << mx << '\n';
        }
    }

    return;
}

int main(void)
{
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);

	ios::sync_with_stdio(false);
	cin.tie(nullptr);

    ///cout << fixed << setprecision(20);

    ///ll tt; cin >> tt; while (tt--)
       solve(++test_case);
    \

    return 0;
}

/**

13 5
5 3 6 3 2 4 2 7 2 7 8 4 5
1 2
1 3
1 4
2 5
5 10
3 6
3 7
4 8
4 9
8 11
8 12
8 13
1 5 6
1 3 4
1 7 8
0 3 9
1 7 8

///

**/