1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| #include <cassert> #include <type_traits> #include <span> #include <stdexcept> #include <memory> #include <vector> #include <iostream>
template<typename T> class SegmentTreeNode { static_assert(std::is_arithmetic_v<T>, "SegmentTreeNode requires an arithmetic type"); const std::span<T> vec; T _sum = 0; T pending_change = 0; const size_t left, right, length, mid; std::unique_ptr<SegmentTreeNode> left_child_ptr{}, right_child_ptr{}; bool initialized = false; public: SegmentTreeNode(const std::span<T> v, const size_t l, const size_t r) : vec(v), left(l), right(r), length(r-l), mid(l+(r-l)/2) { if(l>r || !v.size() || r>v.size()-1) throw std::invalid_argument("Invalid SegmentTreeNode::SegmentTreeNode argument"); } explicit SegmentTreeNode(const std::span<T> v) : SegmentTreeNode(v, 0, v.size()-1) {} void range_add(const size_t lb, const size_t rb, const T n) { if (lb > rb || lb < left || rb > right) throw std::invalid_argument("Invalid SegmentTreeNode::range_add argument"); if (lb == left && rb == right) return add_pending(n); _sum += n * (rb - lb + 1); if (lb <= mid) left_child()->range_add(lb, std::min(rb, mid), n); if (rb > mid) right_child()->range_add(std::max(lb, mid + 1), rb, n); } T range_sum(const size_t lb, const size_t rb) { if (lb > rb || lb < left || rb > right) throw std::invalid_argument("Invalid SegmentTreeNode::range_sum argument"); if (lb == left && rb == right) return sum(); if (pending_change) { left_child()->add_pending(pending_change); right_child()->add_pending(pending_change); _sum += pending_change * (length + 1); pending_change = 0; } T rs = 0; if (lb <= mid) rs += left_child()->range_sum(lb, std::min(rb, mid)); if (rb > mid) rs += right_child()->range_sum(std::max(lb, mid + 1), rb); return rs; } T sum() { if (!initialized) { if (length) _sum = left_child()->sum() + right_child()->sum(); else _sum = vec[left]; initialized = true; } return _sum + pending_change * (length + 1); } SegmentTreeNode* left_child() { if (!length) throw std::invalid_argument("cannot create subtree because the node is leaf."); if (!left_child_ptr) left_child_ptr = std::make_unique<SegmentTreeNode>(vec, left, mid); return left_child_ptr.get(); } SegmentTreeNode* right_child() { if (!length) throw std::invalid_argument("cannot create subtree because the node is leaf."); if (!right_child_ptr) right_child_ptr = std::make_unique<SegmentTreeNode>(vec, mid + 1, right); return right_child_ptr.get(); } void add_pending(const uint64_t n) { pending_change += n; } };
int main() {
std::vector<uint64_t> a; uint64_t n, m; std::cin >> n >> m; a.reserve(n); while(n--){ uint64_t x; std::cin >> x; a.emplace_back(x); } SegmentTreeNode<uint64_t> tree(a); while(m--){ uint64_t t, x, y, k; std::cin >> t; switch(t){ case 1: std::cin >> x >> y >> k; tree.range_add(x-1, y-1, k); break; case 2: std::cin >> x >> y; std::cout << tree.range_sum(x-1, y-1) << std::endl; break; } } return 0; }
|