Cod sursa(job #2046686)

Utilizator retrogradLucian Bicsi retrograd Data 23 octombrie 2017 23:49:56
Problema Heavy Path Decomposition Scor 10
Compilator cpp Status done
Runda Arhiva educationala Marime 4.2 kb
#include <bits/stdc++.h>

using namespace std;

struct HeavyLight {
    vector<int> jump, sub, depth, lin, parent;
    vector<vector<int>> G;
    bool processed = false;

    HeavyLight(int n) : 
        jump(n), sub(n), depth(n), lin(n),
        parent(n), G(n) {}

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

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

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

    // 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 (jump[a] != jump[b]) {
            if (depth[jump[a]] < depth[jump[b]]) swap(a, b);

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

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

        return ret;
    }

    int GetLCA(int a, int b) {
        while (jump[a] != jump[b]) {
            if (depth[jump[a]] < depth[jump[b]])
                swap(a, b);
            a = parent[jump[a]];
        }
        return depth[a] < depth[b] ? a : b;
    }

    int dfs_sub(int node, int par) {
        sub[node] = 1; parent[node] = par;
        
        if (par != -1) {
            G[node].erase(find(G[node].begin(), G[node].end(), par));
            depth[node] = 1 + depth[par];
        }
        
        for (auto vec : G[node])
            sub[node] += dfs_sub(vec, node);

        return sub[node];
    }

    int timer = 0;
    void dfs_jump(int node, int j) {
        jump[node] = j; lin[node] = timer++;

        iter_swap(G[node].begin(), max_element(G[node].begin(), G[node].end(),
            [&](int a, int b) { return sub[a] < sub[b]; }));

        for (auto vec : G[node])
            dfs_jump(vec, vec == G[node].front() ? j : vec);
    }
};

map<int, int> CompressTree(HeavyLight& hl, vector<int> v) {
    auto cmp = [&](int a, int b) { 
        return hl.lin[a] < hl.lin[b]; 
    };
    sort(v.begin(), v.end(), cmp);
    
    for (int i = (int)v.size() - 1; i > 0; --i)
        v.push_back(hl.GetLCA(v[i - 1], v[i]));
    
    sort(v.begin(), v.end(), cmp);
    v.erase(unique(v.begin(), v.end()), v.end());
    
    map<int, int> ret;
    for (int i = 0; i < (int)v.size(); ++i) 
        ret[v[i]] = (i == 0 ? -1 : hl.GetLCA(v[i - 1], v[i]));
    return ret;
}

int main() {
    ifstream cin("heavypath.in");
    ofstream cout("heavypath.out");

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

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

    hl.Preprocess();
    cerr << "DONS" << endl;
    const int kMagic = 512;
    vector<int> aug(n);

    for (int i = 0; i < m; i += kMagic) {
        vector<tuple<int, int, int>> qs;
        
        vector<int> sub;
        for (int j = i; j < m && j < i + kMagic; ++j) {
            int t, a, b; cin >> t >> a >> b;
            sub.push_back(--a); if (t == 1) sub.push_back(--b);
            qs.emplace_back(t, a, b);
        }

        sort(sub.begin(), sub.end());
        sub.erase(unique(sub.begin(), sub.end()), sub.end());

        auto T = CompressTree(hl, sub);

        for (auto& p : T) {
            int node = p.first, anc = p.second;
            aug[node] = 0;
            for (node = hl.parent[node]; node != anc; node = hl.parent[node])
                aug[node] = max(aug[node], val[node]);
        }

        for (auto q : qs) {
            int t, a, b; tie(t, a, b) = q;
            if (t == 0) val[a] = b;
            else {
                int res = 0;
                while (a != b) {
                    if (hl.depth[a] < hl.depth[b]) swap(a, b);
                    res = max(res, val[a]);
                    res = max(res, aug[a]);
                    a = T[a]; 
                }
                cout << max(res, val[a]) << '\n';
            }
        }

    } 
    
    return 0;
}