Cod sursa(job #2712254)

Utilizator flibiaVisanu Cristian flibia Data 25 februarie 2021 15:15:14
Problema Heavy Path Decomposition Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 3.92 kb
#include <bits/stdc++.h>
#define ll long long 
#define fi first
#define se second

using namespace std;

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

const int N = 1e5 + 5;

int n, m, chainsNr;
vector<int> v[N];
int depth[N], dim[N], chainId[N];
vector<int> chains[N];
vector<int> aint[N];
int dad[N];
int values[N];

void dfs(int node, int parent = 0) {
    dad[node] = parent; 
    depth[node] = depth[parent] + 1;
    dim[node] = 1;

    int bestSon = 0;
    for (auto son : v[node]) {
        if (!depth[son]) {
            dfs(son, node);
            dim[node] += dim[son];

            if (dim[son] > dim[bestSon]) {
                bestSon = son;
            }
        }
    }

    if (bestSon == 0) {
        // pentru o frunza cream un lant nou
        chainId[node] = ++chainsNr;
    } else {
        // altfel unim nodul cu lantul asociat fiului cu dimensiunea subarborelui maxima
        chainId[node] = chainId[bestSon];
    }

    chains[chainId[node]].push_back(node);
}

// pozitia unui nod in lantul sau
int getPosition(int node) {
    return depth[node] - depth[chains[chainId[node]][0]] + 1;
}

// adancimea primului nod din lantul corespunzator unui nod
int chainDepth(int node) {
    return depth[chains[chainId[node]][0]];
}

void update(vector<int> &aint, int st, int dr, int node, int id, int val) {
    if (st == dr) {
        aint[node] = val; 
        return;
    }

    int mid = (st + dr) / 2;
    if (id <= mid) {
        update(aint, st, mid, 2 * node, id, val);
    } else {
        update(aint, mid + 1, dr, 2 * node + 1, id , val);
    }

    aint[node] = max(aint[2 * node], aint[2 * node + 1]);
} 

int query(vector<int> &aint, int st, int dr, int node, int l, int r) {
    if (l <= st && dr <= r) {
        return aint[node];
    }

    int mid = (st + dr) / 2;
    int left = 0, right = 0;
    if (l <= mid) {
        left = query(aint, st, mid, 2 * node, l, r);
    }
    if (r > mid) {
        right = query(aint, mid + 1, dr, 2 * node + 1, l, r);
    }

    return max(left, right);
}

void updateChain(int target, int value) {
    values[target] = value;
    update(aint[chainId[target]], 1, chains[chainId[target]].size(), 1, getPosition(target), values[target]);
}

// primul nod dintr-un lant corespunzator lui node
int firstOnChain(int node) {
    return chains[chainId[node]][0];
}

// x si y sunt pe acelasi lant
int maxOnChain(int x, int y) {
    int id = chainId[x];
    x = getPosition(x);
    y = getPosition(y);

    if (x > y) {
        swap(x, y);
    }

    return query(aint[id], 1, chains[id].size(), 1, x, y);
}

int getMaxValue(int x, int y) {
    int ans = 0;
    
    while (chainId[x] != chainId[y]) {
        // urcam pe lantul care se afla mai jos pe arbore
        if (chainDepth(x) < chainDepth(y)) {
            swap(x, y);
        }
    
        ans = max(ans, maxOnChain(firstOnChain(x), x));
        // urcam pe lantul urmator
        x = dad[firstOnChain(x)];
    }

    ans = max(ans, maxOnChain(x, y));

    return ans;
}

int main() {
    in >> n >> m;
    for (int i = 1; i <= n; i++) {
        in >> values[i]; 
    }

    for (int i = 1, x, y; i < n; i++) {
        in >> x >> y;
        v[x].push_back(y);
        v[y].push_back(x);
    }

    dfs(1);
    for (int i = 1; i <= chainsNr; i++) {
        // ordonam nodurile in ordine crescatoare adancimii lor
        reverse(chains[i].begin(), chains[i].end());

        // contruim arborele de intervale pentru lantul curent
        aint[i] = vector<int>(4 * (int) chains[i].size() + 1, 0);

        for (auto node : chains[i]) {
            updateChain(node, values[node]);
        }
    }

    for (int t, x, y; m--;) {
        in >> t >> x >> y;
        if (t == 0) {
            updateChain(x, y);
        } else {
            out << getMaxValue(x, y) << '\n';
        }
    }
    
    return 0;
}