Cod sursa(job #1694715)

Utilizator radarobertRada Robert Gabriel radarobert Data 25 aprilie 2016 20:56:39
Problema Heavy Path Decomposition Scor 40
Compilator cpp Status done
Runda Arhiva educationala Marime 4.45 kb
#include <cstdio>
#include <vector>
#include <cmath>

using namespace std;

const int MAXN = 100100;

int depth[MAXN];
int sub[MAXN];
int value[MAXN];
int special[MAXN];
int first_pos[MAXN];
int last_pos[MAXN];
int rmq[20][4 * MAXN];
int path_id[MAXN];
int path_pos[MAXN];
int path_start[MAXN];
int order[MAXN];
int init_value[MAXN];
int aint[4 * MAXN];
int ln[MAXN];
int up_path[MAXN];
int father[MAXN];
vector<int> g[MAXN];
int n;

int counter = 0;
int path = 1;
int pos = 0;
int counter2 = 0;

void dfs(int node)
{
    first_pos[node] = ++counter;
    rmq[0][counter] = node;
    int i = 0;

    for (auto &it: g[node])
        if (it != father[node])
        {
            father[it] = node;
            depth[it] = depth[node] + 1;
            dfs(it);
            sub[node] += sub[it];
            if (sub[it] > sub[i])
                i = it;

            rmq[0][++counter] = node;
            last_pos[node] = counter;
        }
    if (i == 0)
        sub[node] = 1;
    else
        special[node] = i;
}

void HLD(int node)
{
    if (path_id[node] == 0)
        path_id[node] = path;
    path_pos[node] = ++pos;
    order[node] = ++counter2;
    init_value[counter2] = value[node];

    if (special[node])
        HLD(special[node]);

    for (auto &it: g[node])
        if (it != special[node] && it != father[node])
        {
            path++;
            path_start[path] = counter2 + 1;
            up_path[path] = node;
            pos = 0;
            HLD(it);
        }
}

void buildTree(int i, int left, int right)
{
    if (left == right)
    {
        aint[i] = init_value[left];
        return;
    }
    int mid = (left + right) / 2;
    buildTree(2 * i, left, mid);
    buildTree(2 * i + 1, mid+1, right);

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

int Min(int a, int b)
{
    if (depth[a] < depth[b])
        return a;
    return b;
}

void initRMQ()
{
    for (int i = 2; i <= counter; i++)
        ln[i] = ln[i/2] + 1;
    int lnn = ln[counter];
    for (int i = 1; i <= lnn; i++)
        for (int j = 1; j <= counter; j++)
        {
            if (j + (1<<i) > counter + 1)
                break;
            rmq[i][j] = Min(rmq[i-1][j], rmq[i-1][j + (1 << (i-1))]);
        }
}

int lca(int a, int b)
{
    int left = first_pos[a];
    int right = first_pos[b];
    if (left > right)
        swap(left, right);
    int l = ln[right - left + 1];
    return Min(rmq[l][left], rmq[l][right - (1<<l) + 1]);
}

int qleft, qright, qval;

void update(int i, int left, int right)
{
    if (right < qleft || left > qleft)
        return;
    if (left == right)
    {
        aint[i] = qval;
        return;
    }

    int mid = (left + right) / 2;
    update(2*i, left, mid);
    update(2*i+1, mid+1, right);
    aint[i] = max(aint[2*i], aint[2*i+1]);
}

int query_tree(int i, int left, int right)
{
    if (right < qleft || left > qright)
        return 0;
    if (qleft <= left && right <= qright)
        return aint[i];
    int mid = (left + right) / 2;
    return max(query_tree(2*i, left, mid), query_tree(2*i+1, mid+1, right));
}

int query_up(int u, int v)
{
    int ans = 0;
    while (path_id[u] != path_id[v])
    {
        qleft = path_start[path_id[u]];
        qright = qleft + path_pos[u] - 1;
        ans = max(ans, query_tree(1, 1, n));
        u = up_path[path_id[u]];
    }
    qright = path_start[path_id[u]] + path_pos[u] - 1;
    qleft = path_start[path_id[u]] + path_pos[v] - 1;
    ans = max(ans, query_tree(1, 1, n));
    return ans;
}

int query(int x, int y)
{
    int l = lca(x, y);
    return max(query_up(x, l), query_up(y, l));
}

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

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

    dfs(1);
    path_start[1] = 1;
    HLD(1);
    buildTree(1, 1, n);
    initRMQ();

    int t, x, y;
    for (int i = 1; i <= m; i++)
    {
        scanf("%d%d%d", &t, &x, &y);
        if (t == 0)
        {
            qleft = order[x];
            qval = y;
            update(1, 1, n);
        }
        else
        {
            printf("%d\n", query(x, y));
        }
    }

    return 0;
}