Cod sursa(job #1510556)

Utilizator bciobanuBogdan Ciobanu bciobanu Data 25 octombrie 2015 12:12:19
Problema Heavy Path Decomposition Scor 20
Compilator cpp Status done
Runda Arhiva educationala Marime 3.94 kb
#include <cstdio>
#include <algorithm>

using namespace std;

const int Nmax = 100000;
const int Hmax = 1000; // numarul maxim de carari
const int NIL = -1;

struct Edge {
    int v, next;
};

Edge l[2 * Nmax - 2];   // liste de adiacenta alocate static
int adj[Nmax];          // capete de liste
int key[Nmax];          // valorile date
int father[Nmax];       // father[u] = parintele nodului u
int depth[Nmax];        // depth[u] = adancimea nodului u
int siz[Nmax];          // siz[u] = marimea subarborelui cu radacina u
int path[Nmax];         // path[u] = cararea careia ii apartine u
int lenPath[Nmax];      // lenPath[i] = lungimea cararii i
int nPaths;             // numarul total de carari
int posPath[Nmax];      // pozitia nodului u in cararea careia ii apartine
int startPath[Nmax];    // startPath[i] = nodul de start din cararea i
int T[Hmax][2 * Nmax];  // arbore de intervale pentru fiecare cale

void addEdge(int u, int v, int pos) {
    l[pos].v = v;
    l[pos].next = adj[u];
    adj[u] = pos;
}

void dfs(int u) {
    int heavySize = 0, i, v;

    siz[u] = 1;
    path[u] = NIL;

    for (i = adj[u]; i != NIL; i = l[i].next) {
        v = l[i].v;
        if (father[v] == NIL) {
            father[v] = u;
            depth[v] = depth[u] + 1;
            dfs(v);
            siz[u] += siz[v];
            if (heavySize < siz[v]) {
                heavySize = siz[v];
                path[u] = path[v];
            }
        }
    }
    if (path[u] == NIL) {
        path[u] = nPaths++;
    }
    posPath[u] = lenPath[path[u]]++;
}

void buildHPD(int n) {
    int i;

    father[0] = 0;
    depth[0] = 0;
    dfs(0);

    for (i = 0; i < n; i++) { // oglidim caile
        posPath[i] = lenPath[path[i]] - posPath[i] - 1;
        if (posPath[i] == 0) {
            startPath[path[i]] = i;
        }
    }
}

void buildSegmentedTrees(int n) {
    int i, j;

    for (i = 0; i < n; i++) {
        T[path[i]][posPath[i] + lenPath[path[i]]] = key[i];
    }
    for (i = 0; i < nPaths; i++) {
        for (j = lenPath[i] - 1; j > 0; j--) {
            T[i][j] = max(T[i][2 * j], T[i][2 * j + 1]);
        }
    }
}

void update(int u, int key) {
    int p = path[u];
    int q = posPath[u] + lenPath[p], x;

    T[p][q] = key;
    while (q > 1) {
        x = q / 2;
        T[p][x] = max(T[p][q], T[p][q ^ 1]);
        q = x;
    }
}

int segQuery(int path, int u, int v) {
    int answer = 0;

    if (u > v) {
        swap(u, v);
    }

    u += lenPath[path];
    v += lenPath[path] + 1;
    while (u < v) {
        if (u & 1) {
            answer = max(answer, T[path][u]);
            u++;
        }
        if (v & 1) {
            v--;
            answer = max(answer, T[path][v]);
        }
        u >>= 1;
        v >>= 1;
    }
    return answer;
}

int query(int u, int v) {
    if (depth[startPath[path[u]]] < depth[startPath[path[v]]]) {
        swap(u, v);
    }
    if (path[u] == path[v]) {
        return segQuery(path[u], posPath[u], posPath[v]);
    } else { // u apartine caii celei mai adanci
        return max(segQuery(path[u], 0, posPath[u]), query(father[startPath[path[u]]], v));
    }
}

int main(void) {
    freopen("heavypath.in", "r", stdin);
    freopen("heavypath.out", "w", stdout);
    int n, m, i;
    int tip, u, v;

    scanf("%d%d", &n, &m);
    for (i = 0; i < n; i++) {
        adj[i] = NIL;
        father[i] = NIL;
        scanf("%d", &key[i]);
    }
    for (i = 1; i < n; i++) {
        scanf("%d%d", &u, &v);
        addEdge(u - 1, v - 1, 2 * i - 2);
        addEdge(v - 1, u - 1, 2 * i - 1);
    }

    buildHPD(n);
    buildSegmentedTrees(n);

    for (i = 0; i < m; i++) {
        scanf("%d%d%d", &tip, &u, &v);
        if (tip == 0) {
            update(u - 1, v);
        } else {
            printf("%d\n", query(u - 1, v - 1));
        }
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}