Cod sursa(job #3223755)

Utilizator Dragono63Stanciu Rares Stefan Dragono63 Data 13 aprilie 2024 15:21:11
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.42 kb
#ifndef LOCAL
    #pragma GCC optimize("O3")
    #pragma GCC target("avx2")
#endif

#ifdef LOCAL
    #define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>
#define pb push_back
#define pii pair<int, int>
using ll = long long;
using ci = const int;
using cll = const long long;

using namespace std;

/*******************************/
// INPUT / OUTPUT

#ifndef LOCAL
    ifstream in("heavypath.in");
    ofstream out("heavypath.out");
    #define cin in
    #define cout out
#endif
/*******************************/
/// GLOBAL DECLARATIONS

int N, Q;

struct Node
{
    int val, w, h, par, idx, care;

    vector <int> adj;
};

struct ArbInt
{
    inline int next_power_of_two(int n)
    {
        int p = 1;
        while (p <= n)
            p <<= 1;
        return p;
    }

    int offset;
    vector <int> data;

    ArbInt(int n)
    {
        offset = next_power_of_two(n);
        data.resize(2 * offset);
    }

    inline void _update(int node, int st, int dr, int pos, int val)
    {
        if (st == dr)
        {
            data[node] = val;
            return;
        }

        int mid = (st + dr) / 2;
        if (pos <= mid)
            _update(2 * node, st, mid, pos, val);
        else
            _update(2 * node + 1, mid + 1, dr, pos, val);

        data[node] = max(data[2 * node], data[2 * node + 1]);
        return;
    }

    inline void update(int pos, int val)
    {
        _update(1, 0, offset - 1, pos, val);
    }

    inline int _query(int node, int st, int dr, int q_st, int q_dr)
    {
        if (dr < q_st || q_dr < st) return 0;

        if (q_st <= st && dr <= q_dr)
            return data[node];

        int mid = (st + dr) / 2;
        int rasp_st = _query(2 * node, st, mid, q_st, q_dr);
        int rasp_dr = _query(2 * node + 1, mid + 1, dr, q_st, q_dr);
        return max(rasp_st, rasp_dr);
    }

    inline int query(int q_st, int q_dr)
    {
        return _query(1, 0, offset - 1, q_st, q_dr);
    }
};

struct HeavyPathDecomp
{
    vector <int> reps;
    vector <Node> v;
    ArbInt arb = ArbInt(5);

    HeavyPathDecomp(int n)
    {
        v.resize(n);
        arb = ArbInt(n);
    }

    inline void dfs(int node, int par, int h)
    {
        v[node].h = h;
        v[node].par = par;

        v[node].w = 1;
        for (auto u: v[node].adj)
        {
            if (u == par) continue;

            dfs(u, node, h + 1);

            v[node].w += v[u].w;
        }
    }

    inline void imparte(int node, int par, int &timp, int &lant)
    {
        if (reps.size() == lant)
            reps.push_back(node);

        v[node].idx = timp ++;
        v[node].care = lant;

        int best_w = -1, best = -1;
        for (auto u: v[node].adj)
        {
            if (u == par) continue;

            if (best_w < v[u].w)
            {
                best_w = v[u].w;
                best = u;
            }
        }

        if (best != -1)
        {
            imparte(best, node, timp, lant);

            for (auto u: v[node].adj)
            {
                if (u == par || u == best) continue;

                imparte(u, node, timp, ++ lant);
            }
        }
    }

    inline void init()
    {
        dfs(0, -1, 0);

        int timp = 0, lant = 0;
        imparte(0, -1, timp, lant);

        int rep;
        for (int node = 0 ; node < v.size() ; ++ node)
        {
            rep = reps[v[node].care];
            arb.update(v[rep].idx + v[node].h - v[rep].h, v[node].val);
        }
    }

    inline void update(int node, int val)
    {
        int rep = reps[v[node].care];
        v[node].val = val;
        arb.update(v[rep].idx + v[node].h - v[rep].h, v[node].val);
    }

    inline int query(int a, int b)
    {
        int rep_a = reps[v[a].care];
        int rep_b = reps[v[b].care];

        int ans = -1;
        while (rep_a != rep_b)
        {
            if (v[rep_a].h < v[rep_b].h)
            {
                swap(a, b);
                swap(rep_a, rep_b);
            }

            ans = max(ans, arb.query(v[rep_a].idx, v[rep_a].idx + v[a].h - v[rep_a].h));
            a = v[rep_a].par;
            rep_a = reps[v[a].care];
        }

        if (v[a].h > v[b].h)
        {
            swap(a, b);
            swap(rep_a, rep_b);
        }

        ans = max(ans, arb.query(v[rep_a].idx + v[a].h - v[rep_a].h, v[rep_b].idx + v[b].h - v[rep_b].h));
        return ans;
    }
};

/*******************************/
/// FUNCTIONS

void ReadInput();
void Solution();
void Output();
/*******************************/
///-------------------------------------
inline void ReadInput()
{
    cin >> N >> Q;
}
///-------------------------------------
inline void Solution()
{
    HeavyPathDecomp hvy = HeavyPathDecomp(N);

    for (int i = 0 ; i < N ; ++ i)
        cin >> hvy.v[i].val;

    int a, b;
    for (int i = 1 ; i < N ; ++ i)
    {
        cin >> a >> b;

        a --; b --;
        hvy.v[a].adj.push_back(b);
        hvy.v[b].adj.push_back(a);
    }

    hvy.init();
    int tip;
    while (Q --)
    {
        cin >> tip >> a >> b;

        if (tip == 0)
        {
            a --;
            hvy.update(a, b);
        }
        else
        {
            a --; b --;
            cout << hvy.query(a, b) << "\n";
        }
    }
}
///-------------------------------------
inline void Output()
{

}
///-------------------------------------
int main()
{
    #ifndef LOCAL
        ios::sync_with_stdio(false);
        cin.tie(NULL);
        cout.tie(NULL);
    #endif
    ReadInput();
    Solution();
    Output();
    return 0;
}