Cod sursa(job #2501000)

Utilizator horiacoolNedelcu Horia Alexandru horiacool Data 28 noiembrie 2019 22:24:02
Problema Heavy Path Decomposition Scor 20
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 8.45 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <utility>
#include <algorithm>
 
namespace segment_tree {
 
template <typename Tinfo>
class DefaultCombiner {
 public:
    Tinfo operator()(Tinfo const &lsh, Tinfo const &rsh) {
        return std::max(lsh, rsh);
    }
};
 
template <typename Tinfo, typename Combiner = DefaultCombiner<Tinfo> >
class SegmentTree {
 private:
 public:
    int size_;
    std::vector<Tinfo> tree_;
 
    /*
     * Function that compute an aggregate, such as max/min/sum,
     * of the interval [lsh, rsh].
     */
    Combiner combine_;
 
 public:
    // Default Constructor
    SegmentTree();
 
    // Constructor
    SegmentTree(std::vector<Tinfo> array);
 
    // Destructor
    ~SegmentTree();
 
    /*
     * Build a segment tree from array.
     *
     * @param array // given array to build.
     */
    void build(std::vector<Tinfo> array);
 
    /**
     * Update value of element from position p.
     * 
     * @param p, value // Set value at position p.
     */
    void update(int p, int value);
 
    /**
     * Get an aggregate on interval [lsh, rsh).
     * 
     * @param lsh, rsh // left and right bounds of the interval.
     * @return an aggregate on interval [lsh, rsh).
     */
    Tinfo query(int lsh, int rsh);
 
    /*
     * Get size of array used.
     *
     * @return size of array used.
     */
    int size();
};
 
template <typename Tinfo, typename Combiner>
SegmentTree<Tinfo, Combiner>::SegmentTree(): size_(0) {}
 
template <typename Tinfo, typename Combiner>
SegmentTree<Tinfo, Combiner>::SegmentTree(std::vector<Tinfo> array): size_(array.size()), tree_(2 * array.size()) {
    for (int i = 0; i < size_; ++i) {
        tree_[size_ + i] = array[i];
    }
 
    for (int i = size_ - 1; i > 0; --i) {
        tree_[i] = combine_(tree_[i << 1], tree_[ i<< 1 | 1]);
    }
}
 
template <typename Tinfo, typename Combiner>
SegmentTree<Tinfo, Combiner>::~SegmentTree() {}
 
template <typename Tinfo, typename Combiner>
void SegmentTree<Tinfo, Combiner>::build(std::vector<Tinfo> array) {
    size_ = array.size();
    tree_.resize(2 * size_);
 
    for (int i = 0; i < size_; ++i) {
        tree_[size_ + i] = array[i];
    }
 
    for (int i = size_ - 1; i > 0; --i) {
        tree_[i] = combine_(tree_[i << 1], tree_[ i<< 1 | 1]);
    }
}
 
template <typename Tinfo, typename Combiner>
void SegmentTree<Tinfo, Combiner>::update(int p, int value) {
    for (tree_[p += size_] = value, p >>= 1; p > 0; p >>= 1) {
        tree_[p] = combine_(tree_[p << 1], tree_[p << 1 | 1]);
    }
}
 
template <typename Tinfo, typename Combiner>
Tinfo SegmentTree<Tinfo, Combiner>::query(int lsh, int rsh) {
    bool used_lsh = false, used_rsh = false;
    Tinfo ret_lsh, ret_rsh;
 
    for (lsh += size_, rsh += size_; lsh < rsh; lsh >>= 1, rsh >>= 1) {
        if (lsh & 1) {
            if (used_lsh) {
                ret_lsh = combine_(ret_lsh, tree_[lsh++]);
            } else {
                ret_lsh = tree_[lsh++];
                used_lsh = true;
            }
        }
 
        if (rsh & 1) {
            if (used_rsh) {
                ret_rsh = combine_(tree_[--rsh], ret_rsh);
            } else {
                ret_rsh = tree_[--rsh];
                used_rsh = true;
            }
        }
    }
 
    if (used_lsh && used_rsh) {
        return combine_(ret_lsh, ret_rsh);
    } else {
        return (used_lsh)? ret_lsh: ret_rsh;
    }
}
 
template <typename Tinfo, typename Combiner>
int SegmentTree<Tinfo, Combiner>::size() {
    return size_;
}
 
} // namespace segment_tree
 
namespace tree_decomposition_lca {
 
template <typename Tinfo>
class DefaultCombiner {
 public:
    Tinfo operator()(Tinfo const &lsh, Tinfo const &rsh) {
        return std::max(lsh, rsh);
    }
};
 
template <typename Tinfo, typename Combiner = DefaultCombiner<Tinfo> >
class TreeDecompositionLCA {
 private:
 public:
    struct Node {
        std::vector<int> neighbors_;
    };

    int size_;
    /*
     * Function that compute an aggregate, such as max/min/sum,
     * of the interval [lsh, rsh].
     */
    Combiner combine_;
    std::vector<Node> node_;         // each node has a list of neighbours
    std::vector<Tinfo> cost_;        // information of each node
    std::vector<int> depth_;         // depth of each node
    std::vector<int> parent_;        // parent of each node

    /**
     * Depth-first search for father vector build.
     * 
     * @param node - Current node in search.
     */
    void dfs(int node);
 
 public:
    // Constructor
    TreeDecompositionLCA(int size);
 
    // Destructor
    ~TreeDecompositionLCA();
 
    /**
     * Access information associated to existing node.
     * 
     * @param node Node of whose information will be returned.
     * @return reference to information associated to the given node.
     */
    Tinfo& operator[](int node);
 
    /**
     * Adds an edge between two existing nodes.
     *
     * @param src Source node of the edge to be added.
     * @param dst Destination node of the edge to be added.
     */
    void add_edge(int src, int dst);
 
    /**
     * Gets the tree size.
     *
     * @return Number of nodes in the tree.
     */
    int size();
 
    /**
     * Build tree decomposition.
     */
    void build();
 
    /**
     * Update value of node.
     * 
     * @param node, value // Set value of node.
     */
    void update(int node, Tinfo value);
 
    /**
     * Returns an aggregate, such as max/min/sum,
     * of the weights of the nodes or edges on the path
     * from node src to node dst.
     * 
     * @param src Source node.
     * @param dst Destination node.
     * @return max/min/sum of the weights of the nodes or
     * edges on the path from node src to node dst.
     */
    Tinfo query(int src, int dst);
};
 
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::dfs(int node) { 
    for (auto son: node_[node].neighbors_) {
        if (!depth_[son]) { // unvisited son
            depth_[son] = depth_[node] + 1;
            parent_[son] = node;

            dfs(son);
        }
    }
}

template <typename Tinfo, typename Combiner>
TreeDecompositionLCA<Tinfo, Combiner>::TreeDecompositionLCA(int size): size_(size), node_(size),
    cost_(size), depth_(size, 0), parent_(size) {}
 
template <typename Tinfo, typename Combiner>
TreeDecompositionLCA<Tinfo, Combiner>::~TreeDecompositionLCA() {}
 
template <typename Tinfo, typename Combiner>
Tinfo& TreeDecompositionLCA<Tinfo, Combiner>::operator[](int node) {
    return cost_[node];
}
 
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::add_edge(int src, int dst) {
    node_[src].neighbors_.push_back(dst);
    node_[dst].neighbors_.push_back(src);
}
 
template <typename Tinfo, typename Combiner>
int TreeDecompositionLCA<Tinfo, Combiner>::size() {
    return size_;
}
 
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::build() {
    depth_[0] = 1;
    dfs(0);
    parent_[0] = -1;
}
 
template <typename Tinfo, typename Combiner>
void TreeDecompositionLCA<Tinfo, Combiner>::update(int node, Tinfo value) {
    cost_[node] = value;
}
 
template <typename Tinfo, typename Combiner>
Tinfo TreeDecompositionLCA<Tinfo, Combiner>::query(int src, int dst) {
    std::vector<int> path_src;
    std::vector<int> path_dst;
    Tinfo ret;

    while (src != dst) {
        if (depth_[src] > depth_[dst]) {
            path_src.push_back(src);
            src = parent_[src];
        } else {
            path_dst.push_back(dst);
            dst = parent_[dst];
        }
    }

    // get full path from src to dst
    path_src.push_back(src);
    for (auto it = path_dst.rbegin(); it != path_dst.rend(); ++it) {
        path_src.push_back(*it); 
    }

    ret = cost_[path_src[0]];
    for (unsigned int i = 1; i < path_src.size(); ++i) {
        ret = combine_(ret, cost_[path_src[i]]);
    }

    return ret;
}
 
} // namespace tree_decomposition_lca
 
std::ifstream fin("heavypath.in");
std::ofstream fout("heavypath.out");
int main() {
 
    int N, M, val, t, x, y;
    fin >> N >> M;
 
    tree_decomposition_lca::TreeDecompositionLCA<int> treeDecomp(N);
 
    for (int i = 0; i < N; ++i) {
        fin >> treeDecomp[i];
    }
 
    for (int i = 1; i < N; ++i) {
        fin >> x >> y;
        treeDecomp.add_edge(x - 1, y - 1);
    }
 
    treeDecomp.build();
 
    for (int i = 0; i < M; ++i) {
        fin >> t >> x >> y;
 
        if (t) {
            fout << treeDecomp.query(x - 1, y - 1) << '\n';
        } else {
            treeDecomp.update(x - 1, y);
        }
    }
 
    return 0;
}