Cod sursa(job #2837424)

Utilizator andreiomd1Onut Andrei andreiomd1 Data 22 ianuarie 2022 10:33:38
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.89 kb
#include <fstream>
#include <vector>

using namespace std;

ifstream f("heavypath.in");
ofstream g("heavypath.out");

const int NMAX = 1e5 + 1;
const int ROOT = 1;
const int INF = 1e9;

int N, Q, v[NMAX];

vector < int > G[NMAX];

int w[NMAX], Max_S[NMAX], level[NMAX], father[NMAX];

int CNT = 1;
int Id[NMAX], pos[NMAX], First[NMAX], Size[NMAX];

static inline int my_min (int a, int b)
{
    return ((a < b) ? a : b);
}

static inline int my_max (int a, int b)
{
    return ((a > b) ? a : b);
}

class SegmentTree
{
    int *A;

public:
    inline void Construct (int Size)
    {
        A = new int [((Size << 2) + 1)];

        for(int i = 1; i <= (Size << 2); ++i)
            A[i] = -INF;

        return;
    }

    inline void Update (int Node, int a, int b, int pos, int Val)
    {
        if(a == b)
        {
            A[Node] = Val;

            return;
        }

        int mid = ((a + b) >> 1);

        if(pos <= mid)
            Update((Node << 1), a, mid, pos, Val);
        else
            Update(((Node << 1) + 1), mid + 1, b, pos, Val);

        A[Node] = my_max(A[(Node << 1)], A[((Node << 1) + 1)]);

        return;
    }

    inline int Query (int Node, int a, int b, int qa, int qb)
    {
        if(qa <= a && b <= qb)
            return A[Node];

        int mid = ((a + b) >> 1);
        int p_Left = 0, p_Right = 0;

        if(qa <= mid)
            p_Left = Query((Node << 1), a, mid, qa, qb);

        if(qb > mid)
            p_Right = Query(((Node << 1) + 1), mid + 1, b, qa, qb);

        return my_max(p_Left, p_Right);
    }
} AINT[NMAX];

static inline void Add_Edge (int u, int v)
{
    G[u].push_back(v), G[v].push_back(u);

    return;
}

static inline void Read ()
{
    f.tie(nullptr);

    f >> N >> Q;

    for(int i = 1; i <= N; ++i)
        f >> v[i];

    for(int i = 1; i < N; ++i)
    {
        int u = 0, v = 0;
        f >> u >> v;

        Add_Edge(u, v);
    }

    return;
}

static inline void Find (int Node, int from = 0, int lvl = 0)
{
    w[Node] = 1, father[Node] = from, level[Node] = lvl, Max_S[Node] = -1;

    for(auto it : G[Node])
        if(it != from)
        {
            Find(it, Node, lvl + 1);

            w[Node] += w[it];

            if(Max_S[Node] == -1 || (Max_S[Node] != -1 && w[it] > w[Max_S[Node]]))
                Max_S[Node] = it;
        }

    return;
}

static inline void DFS (int Node, int from = 0)
{
    Id[Node] = CNT;
    pos[Node] = ++Size[CNT];

    if(Size[CNT] == 1)
        First[CNT] = Node;

    if(Max_S[Node] != -1)
        DFS(Max_S[Node], Node);
    else
        return;

    for(auto it : G[Node])
        if(it != from && it != Max_S[Node])
            ++CNT, DFS(it, Node);

    return;
}

static inline void HLD ()
{
    Find(ROOT);

    DFS(ROOT);

    for(int i = 1; i <= CNT; ++i)
        AINT[i].Construct(Size[i]);

    for(int i = 1; i <= N; ++i)
        AINT[Id[i]].Update(1, 1, Size[Id[i]], pos[i], v[i]);

    return;
}

static inline void my_swap (int &x, int &y)
{
    x = (x ^ y), y = (x ^ y), x = (x ^ y);

    return;
}

static inline int Query (int x, int y)
{
    if(Id[x] == Id[y])
        return AINT[Id[x]].Query(1, 1, Size[Id[x]], my_min(pos[x], pos[y]), my_max(pos[x], pos[y]));

    if(level[First[Id[x]]] > level[First[Id[y]]])
        my_swap(x, y);

    return my_max(Query(y, First[Id[y]]), Query(father[First[Id[y]]], x));
}

static inline void TestCase ()
{
    bool _type;
    int x, y;

    f >> _type >> x >> y;

    if(_type == 0)
    {
        AINT[Id[x]].Update(1, 1, Size[Id[x]], pos[x], y);

        return;
    }

    g << Query(x, y) << '\n';

    return;
}

static inline void Solve ()
{
    while(Q--)
        TestCase();

    return;
}

int main()
{
    Read();

    HLD();

    Solve();

    return 0;
}