Cod sursa(job #2485898)

Utilizator DavidLDavid Lauran DavidL Data 2 noiembrie 2019 10:33:05
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.13 kb
#include <bits/stdc++.h>
using namespace std;
ifstream fi("heavypath.in");
ofstream fo("heavypath.out");
#define cin fi
#define cout fo

const int NMAX = 1e5 + 5;

int n, q;
vector <int> G[NMAX];
int v[NMAX], p[NMAX], niv[NMAX];
int subarb[NMAX];
int inCeLant[NMAX];
vector <int> noduriLant[NMAX];
int pozInLant[NMAX];
int cntLanturi;

int aint[4 * NMAX];
int decalaj[NMAX];
int st, dr, rez, poz, val;

inline void bagaInLant(int nod, int lant)
{
    inCeLant[nod] = lant;
    noduriLant[lant].push_back(nod);
}

void getLant(int nod)
{
    for (auto v: G[nod])
    {
        if (v != p[nod])
        {
            p[v] = nod;
            niv[v] = niv[nod] + 1;
            getLant(v);
            subarb[nod] += subarb[v];
        }
    }

    if ((G[nod].size() == 1 && nod != 1) || (nod == 1 && n == 1)) // frunza
    {
        subarb[nod] = 1;

        cntLanturi++;
        bagaInLant(nod, cntLanturi);

        return;
    }

    int maxim = 0, unde = 0;
    for (auto v: G[nod])
        if (v != p[nod] && subarb[v] > maxim)
            maxim = subarb[v], unde = v;

    bagaInLant(nod, inCeLant[unde]);
}

void build(int lant, int nod, int l, int r)
{
    if (l == r)
    {
        aint[nod + decalaj[lant]] = v[noduriLant[lant][l]];
        return;
    }

    int mij = (l + r) / 2;

    build(lant, 2 * nod, l, mij);
    build(lant, 2 * nod + 1, mij + 1, r);

    aint[nod + decalaj[lant]] = max(aint[2 * nod + decalaj[lant]], aint[2 * nod + 1 + decalaj[lant]]);
}

void update(int lant, int nod, int l, int r)
{
    if (l == r)
    {
        aint[nod + decalaj[lant]] = val;
        return;
    }

    int mij = (l + r) / 2;
    if (poz <= mij)
        update(lant, 2 * nod, l, mij);
    else
        update(lant, 2 * nod + 1, mij + 1, r);

    aint[nod + decalaj[lant]] = max(aint[2 * nod + decalaj[lant]], aint[2 * nod + 1 + decalaj[lant]]);
}

void query(int lant, int nod, int l, int r)
{
    if (st <= l && r <= dr)
    {
        rez = max(rez, aint[nod + decalaj[lant]]);
        return;
    }

    int mij = (l + r) / 2;
    if (st <= mij)
        query(lant, 2 * nod, l, mij);
    if (dr > mij)
        query(lant, 2 * nod + 1, mij + 1, r);
}

int main()
{
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        cin >> v[i];

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

    getLant(1);

    for (int i = 1; i <= cntLanturi; i++)
    {
        reverse(noduriLant[i].begin(), noduriLant[i].end());

        decalaj[i] = decalaj[i - 1] + 4 * noduriLant[i - 1].size();
    }

    for (int i = 1; i <= cntLanturi; i++)
        for (int j = 0; j < noduriLant[i].size(); j++)
            pozInLant[noduriLant[i][j]] = j;

    for (int i = 1; i <= cntLanturi; i++)
        build(i, 1, 0, noduriLant[i].size() - 1);

    while (q--)
    {
        int t, x, y;
        cin >> t >> x >> y;
        if (t == 0)
        {
            // update: v[x] = y
            poz = pozInLant[x], val = y;
            update(inCeLant[x], 1, 0, noduriLant[inCeLant[x]].size() - 1);
        }
        else
        {
            // query: maxim pe x...y

            // il tin pe x mai jos

            int ansQuery = -1;

            while (inCeLant[x] != inCeLant[y])
            {
                int px = noduriLant[inCeLant[x]][0], py = noduriLant[inCeLant[y]][0];


                if (niv[px] < niv[py])
                    swap(x, y), swap(px, py);

                rez = 0;
                st = 0;
                dr = pozInLant[x];
                query(inCeLant[x], 1, 0, noduriLant[inCeLant[x]].size() - 1);
                ansQuery = max(ansQuery, rez);
                x = p[px];
            }

            // sunt pe acelasi lant
            rez = 0;
            st = min(pozInLant[x], pozInLant[y]);
            dr = max(pozInLant[x], pozInLant[y]);
            query(inCeLant[y], 1, 0, noduriLant[inCeLant[y]].size() - 1);
            ansQuery = max(ansQuery, rez);

            cout << ansQuery << "\n";
        }
    }


    return 0;
}