Cod sursa(job #1503354)

Utilizator stefanzzzStefan Popa stefanzzz Data 15 octombrie 2015 23:01:24
Problema Heavy Path Decomposition Scor 10
Compilator cpp Status done
Runda Arhiva educationala Marime 3.89 kb
#include <stdio.h>
#include <vector>
#define MAXN 100005
#define MAXLOGN 18
#define MAX(a, b) (((a) > (b))?(a):(b))
using namespace std;

int typeq, x, y;
int n, m, v[MAXN], sz[MAXN], dad[MAXN][MAXLOGN], chainNo[MAXN], chainPoz[MAXN], lvl[MAXN];
int chainCnt = 1, chainHead[MAXN];
vector<int> chain[MAXN], aint[MAXN];
vector<int> G[MAXN];

int lca(int x, int y) {
    if(lvl[x] < lvl[y]) swap(x, y);
    for(int i = MAXLOGN - 1; i >= 0; i--)
        if(lvl[x] - (1 << i) >= lvl[y])
            x = dad[x][i];

    if(x == y) return x;
    for(int i = MAXLOGN - 1; i >= 0; i--)
        if(dad[x][i] != dad[y][i]) {
            x = dad[x][i];
            y = dad[y][i];
        }
    return dad[x][0];
}

void DFS(int u, int p) {
    int x = p;
    for(int i = 0; i < MAXLOGN; i++) {
        dad[u][i] = x;
        x = dad[x][i];
    }

    lvl[u] = lvl[p] + 1;
    sz[u] = 1;
    for(auto x: G[u])
        if(x != p) {
            DFS(x, u);
            sz[u] += sz[x];
        }
}

void HLD(int u) {
    if(chain[chainCnt].size() == 1) chainHead[chainCnt] = u;
    chain[chainCnt].push_back(v[u]);
    chainNo[u] = chainCnt;
    chainPoz[u] = chain[chainCnt].size() - 1;

    int heavySon = 0;
    for(auto x: G[u])
        if(x != dad[u][0] && sz[x] > sz[heavySon])
            heavySon = x;

    if(!heavySon) return;
    HLD(heavySon);

    for(auto x: G[u])
        if(x != dad[u][0] && x != heavySon) {
            chain[++chainCnt].push_back(0);
            HLD(x);
        }
}

void build_ai(vector<int> &ai, vector<int> &v, int node, int l, int r) {
    if(l == r) {
        ai[node] = v[l];
        return;
    }
    int mid = (l + r) >> 1;
    build_ai(ai, v, 2 * node, l, mid);
    build_ai(ai, v, 2 * node + 1, mid + 1, r);
    ai[node] = MAX(ai[2 * node], ai[2 * node + 1]);
}

void query_ai(vector<int> &ai, vector<int> &v, int node, int l, int r, int lq, int rq, int &ans) {
    if(lq <= l && r <= rq) {
        ans = MAX(ans, ai[node]);
        return;
    }

    int mid = (l + r) >> 1;
    if(lq <= mid) query_ai(ai, v, 2 * node, l, mid, lq, rq, ans);
    if(mid + 1 <= rq) query_ai(ai, v, 2 * node + 1, mid + 1, r, lq, rq, ans);
}

void update_ai(vector<int> &ai, vector<int> &v, int node, int l, int r, int &pos) {
    if(l == r) {
        ai[node] = v[l];
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update_ai(ai, v, 2 * node, l, mid, pos);
    else update_ai(ai, v, 2 * node + 1, mid + 1, r, pos);
    ai[node] = MAX(ai[2 * node], ai[2 * node + 1]);
}

int upSolve(int u, int v) {
    int ans = 0;
    while(chainNo[u] != chainNo[v]) {
        int x = chainNo[u];
        query_ai(aint[x], chain[x], 1, 1, chain[x].size() - 1, 1, chainPoz[u], ans);
        u = dad[chainHead[x]][0];
    }
    int x = chainNo[u];
    query_ai(aint[x], chain[x], 1, 1, chain[x].size() - 1, chainPoz[v], chainPoz[u], ans);

    return ans;
}

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

    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%d", &v[i]);

    for(int i = 1; i < n; i++) {
        scanf("%d %d", &x, &y);
        G[x].push_back(y);
        G[y].push_back(x);
    }

    DFS(1, 0);
    chain[1].push_back(0);
    HLD(1);

    for(int i = 1; i <= chainCnt; i++) {
        aint[i].resize(chain[i].size() * 2);
        build_ai(aint[i], chain[i], 1, 1, chain[i].size() - 1);
    }

    while(m--) {
        scanf("%d %d %d", &typeq, &x, &y);
        if(typeq) {
            int z = lca(x, y);
            int val1 = upSolve(x, z), val2 = upSolve(y, z);
            printf("%d\n", MAX(val1, val2));
        }
        else {
            int id = chainNo[x], pos = chainPoz[x];
            chain[id][pos] = y;
            update_ai(aint[id], chain[id], 1, 1, chain[id].size() - 1, pos);
        }
    }

    return 0;
}