Cod sursa(job #2749932)

Utilizator SqueekDanielTodasca Daniel SqueekDaniel Data 9 mai 2021 02:46:50
Problema Heavy Path Decomposition Scor 60
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.2 kb
#include <bits/stdc++.h>

#define MAXN 100005

int N, Q;
int V[MAXN];

std::ifstream input ("heavypath.in");
std::ofstream output("heavypath.out");

#define LEFT   2*index
#define RIGHT  2*index+1
#define MIDDLE (left+right)/2
class HPD {
public:
    HPD(const std::vector <std::vector <int>> &graph, int V[]) : graph(graph) {
        this->V.resize(graph.size(), 0);
        tree.resize(graph.size());
        chain.resize(graph.size());
        for (int i=1; i<graph.size(); ++i) this->V[i] = V[i];
        order.resize(graph.size(), 0);
        where.resize(graph.size(), 0);
        parent.resize(graph.size(), 0);
        rang.resize(graph.size(), 0);
        level.resize(graph.size(), 0);
        NChains = 0;
        DFS();
        buildTrees();
    }

    void update(int X, int Y) {
        V[X] = Y;
        update(where[X], order[X], 0, chain[where[X]].size()-1);
    }

    int query(int X, int Y) {
        int ans = INT_MIN;
        int A, B;

        while (where[X] != where[Y]) {
            if (level[chain[where[X]][0]] < level[chain[where[Y]][0]])
                std::swap (X, Y);

            A = 0, B = order[X];
            ans = std::max(ans, query(where[X], A, B, 0, chain[where[X]].size()-1));
            X = parent[chain[where[X]][0]];
        }   return std::max(ans, query(where[X], std::min(order[X], order[Y]), std::max(order[X], order[Y]), 0, chain[where[X]].size()-1));
    }

private:
    int NChains;
    std::vector <int> V, order, where, parent, rang, level;
    std::vector <std::vector <int>> tree, chain;
    std::vector <std::vector <int>> graph;

    void DFS(int vertex = 1, int height = 1) {
        level[vertex] = height;
        bool bLeaf = true;

        int heavy = 0;
        rang[vertex] = 1;
        for (auto adj:graph[vertex])
            if (!level[adj]) {
                DFS(adj, height+1);
                parent[adj] = vertex;

                bLeaf = false;
                if (rang[adj] > rang[heavy]) heavy = adj;
                rang[vertex] += rang[adj];
            }

        if (bLeaf) where[vertex] = ++NChains;
        else where[vertex] = where[heavy];
        chain[where[vertex]].push_back(vertex);
    }

    void init(int treeidx, int left, int right, int index = 1) {
        if (left == right) {
            tree[treeidx][index] = V[chain[treeidx][left]];
            return;
        }

        init (treeidx, left, MIDDLE, LEFT);
        init (treeidx, MIDDLE+1, right, RIGHT);
        tree[treeidx][index] = std::max(tree[treeidx][LEFT], tree[treeidx][RIGHT]);
    }

    void buildTrees() {
        for (int i=1, j; i<=NChains; ++i) {
            std::reverse(chain[i].begin(), chain[i].end());
            for (j=0; j<chain[i].size(); ++j)
                order[chain[i][j]] = j;

            tree[i].resize(4*chain[i].size() + 5);
            init(i, 0, chain[i].size()-1);
        }
    }

    void update(int treeidx, int pos, int left, int right, int index = 1) {
        if (left == right) {
            tree[treeidx][index] = V[chain[treeidx][left]];
            return;
        }

        if (pos <= MIDDLE) update(treeidx, pos, left, MIDDLE, LEFT);
        else               update(treeidx, pos, MIDDLE+1, right, RIGHT);
        tree[treeidx][index] = std::max(tree[treeidx][LEFT], tree[treeidx][RIGHT]);
    }

    int query(int treeidx, int A, int B, int left, int right, int index = 1) {
        if (A <= left && right <= B)
            return tree[treeidx][index];

        int max = INT_MIN;
        if (A <= MIDDLE) max = query(treeidx, A, B, left, MIDDLE, LEFT);
        if (MIDDLE < B)  max = std::max(max, query(treeidx, A, B, MIDDLE+1, right, RIGHT));
        return max;
    }
};

int main()
{
    input >> N >> Q;
    for (int i=1; i<=N; ++i)
        input >> V[i];

    std::vector <std::vector <int>> graph;
    graph.resize(N+1);
    for (int i=1, X, Y; i<N; ++i)
        input >> X >> Y, graph[X].push_back(Y), graph[Y].push_back(X);

    auto hpd = HPD(graph, V);

    for (int i=1, type, X, Y; i<=Q; ++i) {
        input >> type >> X >> Y;
        if (type) output << hpd.query(X, Y) << '\n';
        else hpd.update(X, Y);
    }

    return 0;
}