Cod sursa(job #1681989)

Utilizator AlexandruValeanuAlexandru Valeanu AlexandruValeanu Data 9 aprilie 2016 21:24:07
Problema Heavy Path Decomposition Scor 100
Compilator cpp Status done
Runda Arhiva educationala Marime 7.44 kb
#include <bits/stdc++.h>

using namespace std;

template<typename T>
class Node
{
public:

    T key;
    bool lazy;
    int length;
};

template<typename T>
void lazyUpdate(Node<T> &S, Node<T> &L, Node<T> &R);

template<typename T>
Node<T> join(Node<T> L, Node<T> R);

template<typename T>
void updateNode(Node<T> &S, const T &value);

template<typename T>
Node<T> realValue(const Node<T> &S);

template<typename T>
class SegmentTree
{
private:

    void update(int node, int l, int r, int st, int dr, const T& value)
    {
        if (st <= l && r <= dr)
        {
            updateNode(tree[node], value);
        }
        else
        {
            lazyUpdate(tree[node], tree[2 * node], tree[2 * node + 1]);

            int m = (l + r) / 2;

            if (st <= m)
                update(2 * node, l, m, st, dr, value);

            if (m < dr)
                update(2 * node + 1, m + 1, r, st, dr, value);

            tree[node] = join(tree[2 * node], tree[2 * node + 1]);
        }
    }

    void build(int node, int l, int r, const vector<T> &keys)
    {
        tree[node].length = r - l + 1;

        if (l == r)
        {
            updateNode(tree[node], keys[l]);
        }
        else
        {
            int m = (l + r) / 2;

            build(2 * node, l, m, keys);
            build(2 * node + 1, m + 1, r, keys);

            tree[node] = join(tree[2 * node], tree[2 * node + 1]);
        }
    }

    Node<T> query(int node, int l, int r, int st, int dr)
    {
        if (st <= l && r <= dr)
            return realValue(tree[node]);
        else
        {
            lazyUpdate(tree[node], tree[2 * node], tree[2 * node + 1]);
            Node<T> solution;

            int m = (l + r) / 2;

            if (st <= m && m < dr)
                solution = join(query(2 * node, l, m, st, dr), query(2 * node + 1, m + 1, r, st, dr));
            else
            {
                if (st <= m)
                    solution = query(2 * node, l, m, st, dr);
                else
                    solution = query(2 * node + 1, m + 1, r, st, dr);
            }

            tree[node] = join(tree[2 * node], tree[2 * node + 1]);

            return solution;
        }
    }

public:

    vector<Node<T>> tree;
    int N;

    SegmentTree() : tree(), N() {
    }

    SegmentTree(const vector<T> &keys) : tree(), N() {

        this->N = keys.size();
        tree.resize(4 * N, Node<T>());

        build(1, 0, N - 1, keys);
    }

    void update(const int x, const int y, const T &value)
    {
        assert(0 <= x && x <= y && y < N);
        update(1, 0, N - 1, x, y, value);
    }

    Node<T> query(const int x, const int y)
    {
        assert(0 <= x && x <= y && y < N);
        return query(1, 0, N - 1, x, y);
    }
};

const int MAX_N = 100000 + 1;

class TYPE;

class TYPE
{
public:

    int Max;
};

namespace HeavyPathDecomposition
{
    vector<SegmentTree<TYPE>> trees; ///type
    vector<vector<int>> graph;

    int depth[MAX_N], size[MAX_N], father[MAX_N];
    TYPE valueNode[MAX_N]; ///type
    int path[MAX_N];

    int posInPath[MAX_N], pathLength[MAX_N], startNode[MAX_N];

    int N, nrPaths;

    void clearHPD()
    {
        N = 0;
        nrPaths = 0;
        trees.clear();
        graph.clear();

        for (int i = 0; i < MAX_N; ++i)
        {
            size[i] = 0;
            father[i] = 0;
            valueNode[i] = TYPE();
            path[i] = 0;
            posInPath[i] = 0;
            pathLength[i] = 0;
            startNode[i] = 0;
        }
    }

    void initHeavyPaths(const int n, const vector<TYPE> &keys) ///type
    {
        N = n;

        for (int i = 1; i <= N; ++i)
        {
            graph.push_back({});
            valueNode[i] = keys[i - 1];
        }
    }

    void addEdge(const int x, const int y)
    {
        assert(1 <= x && x <= N);
        assert(1 <= y && y <= N);

        assert(x != y);

        graph[x].push_back(y);
        graph[y].push_back(x);
    }

    void dfs(int node)
    {
        int heavySon = 0;
        size[node] = 1;

        for (int v : graph[node])
        {
            if (father[v] == 0)
            {
                depth[v] = depth[node] + 1;
                father[v] = node;

                dfs(v);

                size[node] += size[v];

                if (size[v] > size[heavySon])
                    heavySon = v;
            }
        }

        if (heavySon == 0)
            path[node] = nrPaths++;
        else
            path[node] = path[heavySon];

        posInPath[node] = pathLength[ path[node] ]++;
    }

    void buildHeavyPaths()
    {
        father[1] = 1;
        depth[1] = 0;

        dfs(1);

        for (int i = 1; i <= N; ++i)
        {
            posInPath[i] = pathLength[ path[i] ] - posInPath[i] - 1;

            if (posInPath[i] == 0)
                startNode[ path[i] ] = i;
        }
    }

    void buildSegmentTrees()
    {
        vector<vector<TYPE>> pathValues(nrPaths);

        for (int i = 0; i < nrPaths; ++i)
            pathValues[i] = vector<TYPE>(pathLength[i]);

        for (int i = 1; i <= N; ++i)
            pathValues[ path[i] ][ posInPath[i] ] = valueNode[i];

        for (int i = 0; i < nrPaths; ++i)
            trees.push_back(SegmentTree<TYPE>(pathValues[i])); ///type

    }

    void updateChain(int x, int y, const TYPE &value) ///type
    {
        if (depth[ startNode[ path[x] ] ] < depth[ startNode[ path[y] ] ])
            swap(x, y);

        if (path[x] == path[y])
        {
            trees[ path[x] ].update(min(posInPath[x], posInPath[y]), max(posInPath[x], posInPath[y]), value);
        }
        else
        {
            trees[ path[x] ].update(0, posInPath[x], value);
            updateChain(father[ startNode[ path[x] ] ], y, value);
        }
    }

    Node<TYPE> query(int x, int y)
    {
        if (depth[ startNode[ path[x] ] ] < depth[ startNode[ path[y] ] ])
            swap( x, y );

        if ( path[x] == path[y] )
            return trees[ path[x] ].query(min(posInPath[x], posInPath[y]), max(posInPath[x], posInPath[y]));
        else
            return join(trees[ path[x] ].query(0, posInPath[x]), query(father[ startNode[ path[x] ] ], y));
    }
}


template<typename T>
void lazyUpdate(Node<T> &S, Node<T> &L, Node<T> &R)
{
    if (S.lazy)
    {
        /*...*/

        L.lazy = true;
        R.lazy = true;
        S.lazy = false;
    }
}

template<typename T>
Node<T> join(Node<T> L, Node<T> R)
{
    Node<T> solution;

    solution.key.Max = std::max(L.key.Max, R.key.Max);

    return solution;
}

template<typename T>
void updateNode(Node<T> &S, const T &value)
{
    S.key = value;
}

template<typename T>
Node<T> realValue(const Node<T> &S)
{
    Node<T> solution = S;
    return solution;
}

int main()
{
    ifstream in("heavypath.in");
    ofstream out("heavypath.out");

    in.sync_with_stdio(false);

    int N, Q;
    in >> N >> Q;

    HeavyPathDecomposition::clearHPD();

    vector<TYPE> vect;

    for (int i = 0; i < N; ++i)
    {
        int x;
        in >> x;

        vect.push_back({x});
    }

    HeavyPathDecomposition::initHeavyPaths(N, vect);

    for (int i = 1, a, b; i < N; ++i)
    {
        in >> a >> b;

        HeavyPathDecomposition::addEdge(a, b);
    }

    HeavyPathDecomposition::buildHeavyPaths();
    HeavyPathDecomposition::buildSegmentTrees();

    for (int i = 1, tip, a, b; i <= Q; ++i)
    {
        in >> tip >> a >> b;

        if (tip == 0)
            HeavyPathDecomposition::updateChain(a, a, {b});
        else
            out << HeavyPathDecomposition::query(a, b).key.Max << "\n";
    }

    return 0;
}