Cod sursa(job #1560332)

Utilizator StarGold2Emanuel Nrx StarGold2 Data 2 ianuarie 2016 16:09:11
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 6.35 kb
/*
    Dumnezeu cu mila, cine-o sti ce punctaj iau eu
        cu sursa asta de peste 200 de randuri :D
*/
#include <cstdio>
#include <algorithm>
#include <vector>

const int DIM = 131072;
const int INF = 0x3f3f3f3f;
using namespace std;

struct tree {int lazy, value;};
struct rangeNode {int value, cost;};

int NrRange, NrNodes, K, X, Y, NrQuerys, node1, node2;
int NodeValue[DIM], Level[DIM], Heavy[DIM], WhatRange[DIM];
int PosInRange[DIM], Marked[DIM], FatherRange[DIM];
vector <int> Edges[DIM];
vector <tree> Tree[DIM];
vector <rangeNode> Range[DIM];

void build_tree (int range, int node, int left, int right) {
    if (left > right) return;

    if (left == right) {
        Tree[range][node].value = Range[range][left].cost;
        return;
    }

    int middle = left + (right - left) / 2;

    build_tree (range, node * 2, left, middle);
    build_tree (range, node * 2 + 1, middle + 1, right);

    if (Tree[range][node * 2].value >= Tree[range][node * 2 + 1].value)
        Tree[range][node] = Tree[range][node * 2];
    else
        Tree[range][node] = Tree[range][node * 2 + 1];

    return;
}

void update_tree (int range, int node, int left, int right, int start, int finish, int value) {

    if (Tree[range][node].lazy != 0) {
        Tree[range][node].value += Tree[range][node].lazy;

        if (left != right) {
            Tree[range][node * 2].lazy += Tree[range][node].lazy;
            Tree[range][node * 2 + 1].lazy += Tree[range][node].lazy;
        }

        Tree[range][node].lazy = 0;
    }

    if (left > right || left > finish || start > right) return;

    if (start <= left && right <= finish) {
        Tree[range][node].value += value;

        if (left != right) {
            Tree[range][node * 2].lazy += value;
            Tree[range][node * 2 + 1].lazy += value;
        }

        return;
    }

    int middle = left + (right - left) / 2;

    update_tree (range, node * 2, left, middle, start, finish, value);
    update_tree (range, node * 2 + 1, middle + 1, right, start, finish, value);

    if (Tree[range][node * 2].value >= Tree[range][node * 2 + 1].value)
        Tree[range][node] = Tree[range][node * 2];
    else
        Tree[range][node] = Tree[range][node * 2 + 1];

    return;
}

tree query_tree (int range, int node, int left, int right, int start, int finish) {
    tree value1, value2, value3; value3.value = -INF;

    if (Tree[range][node].lazy != 0) {
        Tree[range][node].value += Tree[range][node].lazy;

        if (left != right) {
            Tree[range][node * 2].lazy += Tree[range][node].lazy;
            Tree[range][node * 2 + 1].lazy += Tree[range][node].lazy;
        }

        Tree[range][node].lazy = 0;
    }

    if (left > right || left > finish || start > right) return value3;

    if (start <= left && right <= finish)
        return Tree[range][node];

    int middle = left + (right - left) / 2;

    value1 = query_tree (range, node * 2, left, middle, start, finish);
    value2 = query_tree (range, node * 2 + 1, middle + 1, right, start, finish);

    if (value1.value >= value2.value)
        value3 = value1;
    else
        value3 = value2;

    return value3;
}

void DFS (int node, int level) {
    int ok = 0, maxim = 0, NextRange;
    Level[node] = level;
    Heavy[node] = 1;
    Marked[node] = 1;

    vector <int> :: iterator it;
    for (it = Edges[node].begin(); it != Edges[node].end(); it ++) {
        int NextNode = *it;

        if (!Marked[NextNode]) {
            ok = 1;
            DFS (NextNode, level + 1);

            if (maxim < Heavy[NextNode]) {
                maxim = Heavy[NextNode];
                NextRange = WhatRange[NextNode];
            }

            Heavy[node] += Heavy[NextNode];
        }
    }

    if (ok == 0) {
        NrRange ++;
        WhatRange[node] = NrRange; rangeNode aux;
        aux.value = node; aux.cost = NodeValue[node];
        Range[NrRange].push_back(aux);

        return;
    }
    else {
        WhatRange[node] = NextRange; rangeNode aux;
        aux.value = node; aux.cost = NodeValue[node];
        Range[NextRange].push_back(aux);

        vector <int> :: iterator it;
        for (it = Edges[node].begin(); it != Edges[node].end(); it ++) {
            int NextNode = *it;

            if (WhatRange[NextNode] != 0 && WhatRange[NextNode] != WhatRange[node])
                FatherRange[WhatRange[NextNode]] = node;
        }
    }

    return;
}

int heavy_query (int X, int Y) {
    tree answer;

    if (WhatRange[X] == WhatRange[Y]) {
        if (PosInRange[X] > PosInRange[Y])
            swap (X, Y);

        answer = query_tree (WhatRange[X], 1, 0, Range[WhatRange[X]].size() - 1, PosInRange[X], PosInRange[Y]);
        return answer.value;
    } else {
        if (Level[FatherRange[WhatRange[X]]] < Level[FatherRange[WhatRange[Y]]])
            swap (X, Y);

        answer = query_tree (WhatRange[X], 1, 0, Range[WhatRange[X]].size() - 1, 0, PosInRange[X]);
        return max (answer.value, heavy_query (FatherRange[WhatRange[X]], Y));
    }
    return -1;
}

int main () {

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

    scanf ("%d %d", &NrNodes, &NrQuerys);
    for (int i = 1; i <= NrNodes; i ++)
        scanf ("%d", &NodeValue[i]);

    for (int i = 1; i < NrNodes; i ++) {
        scanf ("%d %d", &node1, &node2);

        Edges[node1].push_back(node2);
        Edges[node2].push_back(node1);
    }

    DFS (1, 1);

    for (int i = 1; i <= NrRange; i ++) {
        reverse (Range[i].begin(), Range[i].end());
        Tree[i].resize(Range[i].size() * 4);

        for (int j = 0; j < Range[i].size(); j ++)
            PosInRange[Range[i][j].value] = j;

        build_tree (i, 1, 0, Range[i].size() - 1);
    }

    for (int i = 1; i <= NrQuerys; i ++) {
        scanf ("%d %d %d", &K, &X, &Y);

        switch (K) {
            case 0: {
                update_tree (WhatRange[X], 1, 0, Range[WhatRange[X]].size() - 1, PosInRange[X], PosInRange[X], Y - Range[WhatRange[X]][PosInRange[X]].cost);
                Range[WhatRange[X]][PosInRange[X]].cost = Y;
                break;
            }
            case 1: {
                printf ("%d\n", heavy_query(X, Y));
                break;
            }
        }
    }

    return 0;
}