Cod sursa(job #2415422)

Utilizator IulianOleniucIulian Oleniuc IulianOleniuc Data 25 aprilie 2019 23:17:54
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 5.12 kb
#include <vector>
#include <fstream>

using std::vector;
std::ifstream fin("heavypath.in");
std::ofstream fout("heavypath.out");

inline int min(int x, int y) {
    return x < y ? x : y;
}

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

class SegmTree {
  private:
    int n;
    vector<int> tree;

    void build(int node, int left, int right, vector<int>& v) {
        if (left == right) {
            tree[node] = v[left];
            return;
        }

        int mid = (left + right) / 2;
        build(2 * node, left, mid, v);
        build(2 * node + 1, mid + 1, right, v);
        tree[node] = max(tree[2 * node], tree[2 * node + 1]);
    }

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

        int mid = (left + right) / 2;
        if (pos <= mid)
            update(2 * node, left, mid, pos, val);
        else
            update(2 * node + 1, mid + 1, right, pos, val);
        tree[node] = max(tree[2 * node], tree[2 * node + 1]);
    }

    int query(int node, int left, int right, int qLeft, int qRight) {
        if (left == qLeft && right == qRight)
            return tree[node];

        int mid = (left + right) / 2;
        if (qRight <= mid)
            return query(2 * node, left, mid, qLeft, qRight);
        if (qLeft > mid)
            return query(2 * node + 1, mid + 1, right, qLeft, qRight);

        return max(
            query(2 * node, left, mid, qLeft, mid),
            query(2 * node + 1, mid + 1, right, mid + 1, qRight)
        );
    }

  public:
    void init(vector<int>& v) {
        n = v.size();
        tree.resize(4 * n);
        build(1, 0, n - 1, v);
    }
    
    void update(int pos, int val) {
        update(1, 0, n - 1, pos, val);
    }

    int query(int left, int right) {
        return query(1, 0, n - 1, left, right);
    }
};

class Tree {
  private:
    struct Chain {
        int id;
        int father;

        SegmTree tree;
        vector<int> nodes;

        Chain(int id) {
            this->id = id;
        }
    };

    int n;
    vector<int> depth;
    vector<vector<int>> ad;

    vector<Chain> chains;
    vector<int> chain, pos;

    void setChainFather(int chain, int father) {
        chains[chain].father = father;
    }

    void addChainNode(int chainID, int node) {
        chain[node] = chainID;
        pos[node] = chains[chainID].nodes.size();
        chains[chainID].nodes.push_back(node);
    }

    int dfs(int node, int father) {
        int card = 1;
        depth[node] = depth[father] + 1;

        if (ad[node].size() == 1 && node != 1) {
            chains.push_back(Chain(chains.size()));
            addChainNode(chains.size() - 1, node);
            return card;
        }

        int maxNghb = 0;
        int maxCard = 0;

        for (int nghb : ad[node])
            if (nghb != father) {
                int nowCard = dfs(nghb, node);
                card += nowCard;

                if (nowCard > maxCard) {
                    maxCard = nowCard;
                    maxNghb = nghb;
                }
            }

        addChainNode(chain[maxNghb], node);
        for (int nghb : ad[node])
            if (nghb != father && nghb != maxNghb)
                setChainFather(chain[nghb], node);
        return card;
    }

  public:
    Tree(int n) {
        this->n = n;
        ad.resize(n + 1);
    }

    void addEdge(int x, int y) {
        ad[x].push_back(y);
        ad[y].push_back(x);
    }

    void heavyPath(vector<int>& val) {
        pos.resize(n + 1);
        chain.resize(n + 1);
        depth.resize(n + 1);

        dfs(1, 0);
        for (Chain& chain : chains) {
            vector<int> v;
            v.reserve(chain.nodes.size());

            for (int node : chain.nodes)
                v.push_back(val[node]);
            chain.tree.init(v);
        }
    }

    void update(int node, int val) {
        chains[chain[node]].tree.update(pos[node], val);
    }

    int query(int x, int y) {
        if (chain[x] == chain[y])
            return chains[chain[x]].tree.query(min(pos[x], pos[y]), max(pos[x], pos[y]));
        if (depth[chains[chain[x]].nodes.back()] < depth[chains[chain[y]].nodes.back()])
            return max(chains[chain[y]].tree.query(pos[y], chains[chain[y]].nodes.size() - 1), query(x, chains[chain[y]].father));
        return max(chains[chain[x]].tree.query(pos[x], chains[chain[x]].nodes.size() - 1), query(chains[chain[x]].father, y));
    }
};

int main() {
    int n, q;
    fin >> n >> q;

    Tree tree(n);
    vector<int> val(n + 1);

    for (int i = 1; i <= n; i++)
        fin >> val[i];

    for (int i = 1; i < n; i++) {
        int x, y; fin >> x >> y;
        tree.addEdge(x, y);
    }

    tree.heavyPath(val);
    for (int i = 0; i < q; i++) {
        int t, x, y;
        fin >> t >> x >> y;

        if (t)
            fout << tree.query(x, y) << '\n';
        else
            tree.update(x, y);
    }

    fout.close();
    return 0;
}