// // Created by maximilian on 16.04.22. // #include #include #include "segment_tree.h" SegmentTree::SegmentTree(const std::vector &coords): _nodes() { assert(!coords.empty()); // reserve nodes for a full binary tree with at least as many leaves as intervals size_t num_leaf_nodes = coords.size() -1; size_t num_meta_nodes = std::bit_ceil(num_leaf_nodes) - 1; // Initialize all nodes with zero coverage and dummy interval _nodes.resize(2 * num_meta_nodes + 1, {0, coords[num_leaf_nodes].coord, coords[num_leaf_nodes].coord, 0}); // We initialize the tree from bottom up, keeping track of the index ranges // and the length of the corresponding segment for(Index leaf_node_idx = 0 ; leaf_node_idx < num_leaf_nodes ; ++leaf_node_idx) { _nodes[leaf_node_idx + num_meta_nodes].left_coord = coords[leaf_node_idx].coord; _nodes[leaf_node_idx + num_meta_nodes].right_coord = coords[leaf_node_idx +1].coord; } // Note that there are remaining leafs that represent dummy ranges for(Index node_idx = num_meta_nodes - 1; node_idx != -1 ; --node_idx) { _nodes[node_idx].left_coord = left_child(node_idx).left_coord; _nodes[node_idx].right_coord = right_child(node_idx).right_coord; } assert(_nodes.front().left_coord == coords.front().coord); assert(_nodes.front().right_coord == coords.back().coord); assert(_nodes.front().segment_length() == coords.back().coord - coords.front().coord); } void SegmentTree::add_interval(Interval interval, Index node_idx) { if (interval.left <= _nodes[node_idx].left_coord && _nodes[node_idx].right_coord <= interval.right) { add_coverage(node_idx); } else { if(interval.left < left_child(node_idx).right_coord) { add_interval(interval, left_child_idx(node_idx)); } if(right_child(node_idx).left_coord < interval.right) { add_interval(interval, right_child_idx(node_idx)); } update_covered_length(node_idx); } } void SegmentTree::remove_interval(Interval interval, Index node_idx) { if (interval.left <= _nodes[node_idx].left_coord && _nodes[node_idx].right_coord <= interval.right) { remove_coverage(node_idx); } else { if(interval.left < left_child(node_idx).right_coord) { remove_interval(interval, left_child_idx(node_idx)); } if(right_child(node_idx).left_coord < interval.right) { remove_interval(interval, right_child_idx(node_idx)); } } }