Cod sursa(job #1335435)

Utilizator thewildnathNathan Wildenberg thewildnath Data 5 februarie 2015 15:13:24
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 5.74 kb
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

const int NMAX = 100000;

int parent[NMAX + 1];
int weight[NMAX + 1];
int level[NMAX + 1];
int value[NMAX + 1];
int position[NMAX + 1];
int a[NMAX + 1];

vector <int> graph[NMAX + 1];

struct node
{
    int max;
    int rightBound;
    int leftBound;

    node* leftSon;
    node* rightSon;

    node (int max, int leftBound, int rightBound, node* leftSon, node* rightSon):
        max (max), leftBound (leftBound), rightBound (rightBound),
        leftSon (leftSon), rightSon (rightSon) {}
};

class intervalTree
{
private:
    node* root;

    node* buildTree (int* begin, int* end, int leftBound, int rightBound)
    {
        if (leftBound == rightBound)
            return new node (a[leftBound], leftBound, rightBound, NULL, NULL);
        else
        {
            int med = (leftBound + rightBound) >> 1;

            node* leftSon = buildTree (begin, begin + med - leftBound + 1,
                                       leftBound, med);
            node* rightSon = buildTree (begin + med - leftBound + 1, end,
                                        med + 1, rightBound);

            return new node (max (leftSon->max, rightSon->max),
                             leftBound, rightBound, leftSon, rightSon);
        }
    }

    void update (node* node, int position, int newValue)
    {
        if (node->leftBound == position && node->rightBound == position)
            node->max = newValue;
        else if (node->leftBound <= position && node->rightBound >= position)
        {
            update (node->leftSon, position, newValue);
            update (node->rightSon, position, newValue);

            node->max = max (node->leftSon->max, node->rightSon->max);
        }
    }

    int query (node* node, int leftBound, int rightBound)
    {
        if (leftBound <= node->leftBound && node->rightBound <= rightBound)
            return node->max;
        else
        {
            int ans = 0;

            if (node->leftSon != NULL && node->leftSon->rightBound >= leftBound)
                ans = max(ans, query (node->leftSon, leftBound, rightBound));
            if (node->rightSon != NULL && node->rightSon->leftBound <= rightBound)
                ans = max (ans, query (node->rightSon, leftBound, rightBound));

            return ans;
        }
    }
public:
    void build (int length)
    {
        root = buildTree (a + 1, a + length + 1, 0, length - 1);
    }

    void update (int position, int newValue)
    {
        update (root, position, newValue);
    }

    int query (int left, int right)
    {
        return query (root, left, right);
    }
};

class heavyPath
{
private:
    vector <int> path;
    intervalTree tree;
    bool built;
public:
    int parent;

    heavyPath (int vertex = 0)
    {
        built = false;
        addVertex (vertex);
    }

    void build ()
    {
        if (!built)
        {
            built = true;
            for (int i = 0; i < path.size (); ++i)
                a[i] = value[path[i]];
            this->tree.build (path.size ());
        }
    }

    void addVertex (int vertex)
    {
        this->parent = vertex;
        this->path.push_back (vertex);
    }

    void update (int vertex, int value)
    {
        this->tree.update (position[vertex], value);
    }

    int query (int vertexLeft, int vertexRight)
    {
        return this->tree.query (min (position[vertexLeft], position[vertexRight]),
                                 max (position[vertexLeft], position[vertexRight]));
    }

    int query (int vertexLeft)
    {
        return query (vertexLeft, parent);
    }
};

heavyPath* path[NMAX + 1];

void buildPaths (int vertex)
{
    weight[vertex] = 1;

    if (graph[vertex].size () > 1 || graph[vertex][0] != parent[vertex])
    {
        int maxWeight = 0, bestSon, son;
        for (int i = 0; i < graph[vertex].size (); ++i)
        {
            son = graph[vertex][i];
            if (son != parent[vertex])
            {
                parent[son] = vertex;
                level[son] = level[vertex] + 1;

                buildPaths (son);
                weight[vertex] += weight[son];
                if (weight[son] > maxWeight)
                    maxWeight = weight[son], bestSon = son;
            }
        }

        path[vertex] = path[bestSon];
        position[vertex] = position[bestSon] + 1;
        path[bestSon]->addVertex (vertex);
    }else
    {
        path[vertex] = new heavyPath (vertex);
        position[vertex] = 0;
    }
}

int solve (int vertex1, int vertex2)
{
    int ans = 0;

    while (path[vertex1] != path[vertex2])
    {
        if (level[path[vertex1]->parent] < level[path[vertex2]->parent])
            swap (vertex1, vertex2);
        ans = max (ans, path[vertex1]->query (vertex1));
        vertex1 = parent[path[vertex1]->parent];
    }
    ans = max (ans, path[vertex1]->query (vertex1, vertex2));

    return ans;
}

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

    int n, m, type, x, y;

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

    level[1] = 1;
    buildPaths (1);

    for (int i = 1; i <= n; ++i)
        path[i]->build ();

    for(int i = 1; i <= m; ++i)
    {
        scanf ("%d%d%d", &type, &x, &y);
        if (type == 0)
            path[x]->update (x, y);
        else if (type == 1)
            printf ("%d\n", solve (x, y));
    }

    return 0;
}