Cod sursa(job #2011097)

Utilizator retrogradLucian Bicsi retrograd Data 15 august 2017 04:34:09
Problema Heavy Path Decomposition Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 3.32 kb
#include <bits/stdc++.h>

using namespace std;

class HeavyLight {
    struct Node {
        int jump, subsize, depth, lin, parent;
        vector<int> leg;
    };
    vector<Node> T;
    bool processed;

public:

    HeavyLight(int n) : T(n) {}

    void AddEdge(int a, int b) {
        T[a].leg.push_back(b);
        T[b].leg.push_back(a);
    }

    void Preprocess() {
        assert(dfs_sub(0, -1) == T.size());
        dfs_jump(0, 0);
        processed = true;
    }

    // Gets the position in the HL linearization
    int GetPosition(int node) {
        assert(processed);
        return T[node].lin;
    }

    // Gets an array of ranges of form [li...ri)
    // that correspond to the ranges you would need
    // to query in the underlying structure
    vector<pair<int, int>> GetPathRanges(int a, int b) {
        assert(processed);

        vector<pair<int, int>> ret;
        while (T[a].jump != T[b].jump) {
            if (T[T[a].jump].depth < T[T[b].jump].depth)
                swap(a, b);

            ret.emplace_back(T[T[a].jump].lin, T[a].lin + 1);
            a = T[T[a].jump].parent;
        }

        if (T[a].depth < T[b].depth) swap(a, b);
        ret.emplace_back(T[b].lin, T[a].lin + 1);

        return ret;
    }

private:

    int dfs_sub(int x, int par) {
        auto &node = T[x];
        node.subsize = 1;
        node.parent = par;

        if (par != -1) {
            node.leg.erase(find(begin(node.leg), end(node.leg), par));
            node.depth = 1 + T[par].depth;
        }

        for (auto vec : node.leg)
            node.subsize += dfs_sub(vec, x);

        return node.subsize;
    }

    int timer = 0;
    void dfs_jump(int x, int jump) {
        auto &node = T[x];
        node.jump = jump;
        node.lin = timer++;

        sort(begin(node.leg), end(node.leg),
        //iter_swap(begin(node.leg), max_element(begin(node.leg), end(node.leg),
            [&](int a, int b) { return T[a].subsize > T[b].subsize; });

        for (auto vec : node.leg)
            dfs_jump(vec, vec == node.leg.front() ? jump : vec);
    }
};

class SegmTree {
    vector<int> T;
    int n;

public:

    SegmTree(int n) : T(2 * n), n(n) {}

    void Update(int pos, int val) {
        for (T[pos += n] = val; pos > 1; pos /= 2)
            T[pos / 2] = max(T[pos], T[pos ^ 1]);
    }

    int Query(int b, int e) {
        int res = 0;
        for (b += n, e += n; b < e; b /= 2, e /= 2) {
            if (b % 2) res = max(res, T[b++]);
            if (e % 2) res = max(res, T[--e]);
        }
        return res;
    }
};

int main() {
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);

    int n, m; cin >> n >> m;

    SegmTree st(n);
    HeavyLight hl(n);

    vector<int> vals(n);
    for (int i = 0; i < n; ++i) {
        cin >> vals[i];
    }

    for (int i = 1; i < n; ++i) {
        int a, b; cin >> a >> b;
        hl.AddEdge(a - 1, b - 1);
    }

    hl.Preprocess();

    for (int i = 0; i < n; ++i)
        st.Update(hl.GetPosition(i), vals[i]);

    while (m--) {
        int t, a, b;
        cin >> t >> a >> b;

        if (t == 0) {
            st.Update(hl.GetPosition(a - 1), b);
        } else {
            int ans = 0;
            for (auto p : hl.GetPathRanges(a - 1, b - 1))
                ans = max(ans, st.Query(p.first, p.second));
            cout << ans << '\n';
        }
    }

    return 0;
}