Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <utility>
- #include <vector>
- #include <stack>
- #include <unordered_set>
- #include <cmath>
- #include <tuple>
- #include <cassert>
- #include <algorithm>
- using namespace std;
- using Graph = vector<vector<int>>;
- struct MaxTree {
- // cluster's parent cluster
- vector<int> clusterParents;
- // portal node in parent cluster
- vector<int> clusterPortals;
- // inner cluster trees
- vector<Graph> clusters;
- // links to parent nodes inside clusters
- vector<vector<int>> reverseClusters;
- // maps initial tree nodes to cluster and node inside the cluster
- vector<pair<int, int>> clusterMap;
- // radioactivity of every node of every cluster
- vector<vector<int>> levels;
- // maximum radioactivity on from cluster root to each node in the cluster.
- vector<vector<int>> maxLevels;
- MaxTree(const Graph& tree) : clusterMap(tree.size()), clusterParents(1), clusterPortals(1) {
- int n = tree.size();
- int maxClusterSize = int(round(sqrt(n)));
- int clusterNo = 0;
- // parent of each node in the original tree
- vector<int> parents(n);
- stack<int> queue;
- queue.push(0);
- Graph cluster;
- vector<int> reverseCluster;
- while(!queue.empty()) {
- // get next node
- int node = queue.top();
- queue.pop();
- int parentCluster, parentClusterNode;
- tie(parentCluster, parentClusterNode) = clusterMap[parents[node]];
- // current node is going to be cluster root
- if (node != 0 && (parentCluster != clusterNo || cluster.size() >= maxClusterSize)) {
- clusterNo++;
- // save cluster and start new
- clusters.push_back(move(cluster));
- reverseClusters.push_back(move(reverseCluster));
- cluster = Graph();
- reverseCluster = vector<int>();
- // link to parent cluster
- clusterParents.push_back(parentCluster);
- clusterPortals.push_back(parentClusterNode);
- }
- int clusterNode = cluster.size();
- cluster.push_back(vector<int>());
- if (clusterNode != 0) {
- cluster[parentClusterNode].push_back(clusterNode);
- reverseCluster.push_back(parentClusterNode);
- } else {
- reverseCluster.push_back(0);
- }
- clusterMap[node] = {clusterNo, clusterNode};
- for (int child: tree[node]) {
- if (child == parents[node]) continue;
- parents[child] = node;
- queue.push(child);
- }
- }
- if (cluster.size() > 0) {
- clusters.push_back(move(cluster));
- reverseClusters.push_back(move(reverseCluster));
- }
- for (int i = 0; i < clusters.size(); i++) {
- int clusterSize = clusters[i].size();
- levels.push_back(vector<int>(clusterSize));
- maxLevels.push_back(vector<int>(clusterSize));
- }
- }
- void increase(int c, int v) {
- int cluster, node;
- tie(cluster, node) = clusterMap[c];
- int level = (levels[cluster][node] += v);
- propagateMax(cluster, node, level);
- }
- void propagateMax(int cluster, int start, int level) {
- stack<int> queue;
- queue.push(start);
- while (!queue.empty()) {
- int node = queue.top();
- queue.pop();
- if (maxLevels[cluster][node] >= level) continue;
- maxLevels[cluster][node] = level;
- for (int child : clusters[cluster][node]) {
- queue.push(child);
- }
- }
- }
- int query(int f, int t) {
- int fromCluster, fromNode, toCluster, toNode;
- tie(fromCluster, fromNode) = clusterMap[f];
- tie(toCluster, toNode) = clusterMap[t];
- int topCluster = getTop(clusterParents, fromCluster, toCluster);
- int fromTopNode, toTopNode, fromMaxBottom, toMaxBottom;
- tie(fromTopNode, fromMaxBottom) = walkLeg(fromNode, fromCluster, topCluster);
- tie(toTopNode, toMaxBottom) = walkLeg(toNode, toCluster, topCluster);
- int maxTop = walkElbow(topCluster, fromTopNode, toTopNode);
- return max({fromMaxBottom, toMaxBottom, maxTop});
- }
- vector<int> pathToRoot(const vector<int> &parents, int node) {
- vector<int> result;
- result.push_back(node);
- while (node != 0) {
- node = parents[node];
- result.push_back(node);
- }
- return result;
- }
- int getTop(const vector<int> &parents, int from, int to) {
- vector<int> fromPath, toPath;
- fromPath = pathToRoot(parents, from);
- toPath = pathToRoot(parents, to);
- int result;
- while (!fromPath.empty() && !toPath.empty() && fromPath.back() == toPath.back()) {
- result = fromPath.back();
- fromPath.pop_back();
- toPath.pop_back();
- }
- return result;
- }
- pair<int, int> walkLeg(int node, int cluster, int top) {
- int maxLevel = 0;
- while (cluster != top) {
- maxLevel = max(maxLevel, maxLevels[cluster][node]);
- node = clusterPortals[cluster];
- cluster = clusterParents[cluster];
- }
- return {node, maxLevel};
- }
- int walkElbow(int cluster, int from, int to) {
- const auto &parents = reverseClusters[cluster];
- int topNode = getTop(reverseClusters[cluster], from, to);
- vector<int> fromPath, toPath;
- int fromMax = walkHand(cluster, from, topNode);
- int toMax = walkHand(cluster, to, topNode);
- return max(fromMax, toMax);
- }
- int walkHand(int cluster, int from, int top) {
- int maxLevel = levels[cluster][from];
- while (from != top) {
- assert(from != 0);
- from = reverseClusters[cluster][from];
- maxLevel = max(maxLevel, levels[cluster][from]);
- }
- return maxLevel;
- }
- };
- int main(int argc, char **argv) {
- ios_base::sync_with_stdio(false);
- int n;
- cin >> n;
- Graph mainTree(n);
- for (int i = 0; i < n-1; i++) {
- int f, t;
- cin >> f >> t;
- mainTree[f-1].push_back(t-1);
- mainTree[t-1].push_back(f-1);
- }
- int q;
- cin >> q;
- MaxTree ct(mainTree);
- for (int i = 0; i < q; i++) {
- char c;
- int u,v;
- cin >> c >> u >> v;
- if (c == 'I') {
- ct.increase(u-1, v);
- } else if (c == 'G') {
- cout << ct.query(u-1, v-1) << '\n';
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment