Cod sursa(job #3362711)

Utilizator EricDimiCismaru Eric-Dimitrie EricDimi Data 11 august 2026 14:42:20
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.38 kb
#include <fstream>
#include <algorithm>
#include <vector>

using namespace std;

ifstream fin("heavypath.in");
ofstream fout("heavypath.out");

const int MAX_N = 100000;

inline int max(int x, int y)
{
    return (x > y) ? x : y;
}

inline void swap(int& x, int& y)
{
    x ^= y ^= x ^= y;
}

vector<int> adj[MAX_N + 1],
            path[MAX_N + 1];
int val[MAX_N + 1],
    depth[MAX_N + 1],
    subSize[MAX_N + 1];
int parent[MAX_N + 1],
    idx[MAX_N + 1],
    pos[MAX_N + 1];
int n, q, pathsCount;

struct SegmentTree
{
    int tree[MAX_N << 2 | 1];

    void Build(int node, int left, int right, int pathIdx, int delta)
    {
        if(left == right)
        {
            tree[node + delta] = val[path[pathIdx][left - 1]];
            return;
        }

        int mid = left + ((right - left) >> 1);

        Build(node << 1, left, mid, pathIdx, delta);
        Build(node << 1 | 1, mid + 1, right, pathIdx, delta);

        tree[node + delta] = max(tree[(node << 1) + delta],
                                 tree[(node << 1 | 1) + delta]);
    }

    void Update(int node, int left, int right, int pos, int val, int delta)
    {
        if(left == right)
        {
            tree[node + delta] = val;
            return;
        }

        int mid = left + ((right - left) >> 1);

        if(pos <= mid)
            Update(node << 1, left, mid, pos, val, delta);
        if(pos > mid)
            Update(node << 1 | 1, mid + 1, right, pos, val, delta);

        tree[node + delta] = max(tree[(node << 1) + delta],
                                 tree[(node << 1 | 1) + delta]);
    }

    int Query(int node, int left, int right, int leftQuery, int rightQuery, int delta)
    {
        if(left > rightQuery || right < leftQuery)
            return 0;

        if(leftQuery <= left && right <= rightQuery)
            return tree[node + delta];

        int mid = left + ((right - left) >> 1);

        return max(Query(node << 1, left, mid, leftQuery, rightQuery, delta),
                   Query(node << 1 | 1, mid + 1, right, leftQuery, rightQuery, delta));

    }
};
SegmentTree segTree;
int delay[MAX_N + 1];

void Read()
{
    fin >> n >> q;
    for(int i = 1; i <= n; i++)
        fin >> val[i];
    for(int i = 1; i < n; i++)
    {
        int x, y;
        fin >> x >> y;
        adj[x].push_back(y);
        adj[y].push_back(x);
    }
}

void DFS(int node, int father)
{
    bool leaf = true;
    int heavySon = -1;

    depth[node] = 1 + depth[father];
    subSize[node] = 1;

    for(int son : adj[node])
    {
        if(son == father)
            continue;

        DFS(son, node);

        leaf = false;
        subSize[node] += subSize[son];
        if(heavySon == -1 || subSize[heavySon] < subSize[son])
            heavySon = son;
    }

    if(leaf)
    {
        ++pathsCount;
        path[pathsCount].push_back(node);
        idx[node] = pathsCount;
        return;
    }

    path[idx[heavySon]].push_back(node);
    idx[node] = idx[heavySon];

    for(int son : adj[node])
    {
        if(son == father || son == heavySon)
            continue;
        parent[idx[son]] = node;
    }
}

void MakePaths()
{
    for(int i = 1; i <= pathsCount; i++)
    {
        reverse(path[i].begin(), path[i].end());
        int ind = 0;
        for(int node : path[i])
            pos[node] = ++ind;
        delay[i] = delay[i - 1] + ((int)path[i - 1].size() << 2);
        segTree.Build(1, 1, (int)path[i].size(), i, delay[i]);
    }
}

int Query(int x, int y)
{
    if(idx[x] == idx[y])
    {
        if(pos[x] > pos[y])
            swap(x, y);
        return segTree.Query(1, 1, (int)path[idx[x]].size(), pos[x], pos[y], delay[idx[x]]);
    }

    if(depth[parent[idx[x]]] < depth[parent[idx[y]]])
        swap(x, y);
    return max(segTree.Query(1, 1, (int)path[idx[x]].size(), 1, pos[x], delay[idx[x]]),
               Query(parent[idx[x]], y));
}

void SolveQueries()
{
    while(q--)
    {
        int t, x, y;
        fin >> t >> x >> y;

        if(t == 0)
            segTree.Update(1, 1, (int)path[idx[x]].size(), pos[x], y, delay[idx[x]]);
        else
        if(t == 1)
            fout << Query(x, y) << '\n';
    }
}

int main()
{
    Read();
    DFS(1, 0);
    MakePaths();
    SolveQueries();

    fin.close();
    fout.close();

    return 0;
}