segment_tree.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "statistics/segment_tree.h"
  8. namespace Statistic {
  9. namespace {
  10. constexpr auto kMinArraySize = size_t(30);
  11. } // namespace
  12. SegmentTree::SegmentTree(std::vector<ChartValue> array)
  13. : _array(std::move(array)) {
  14. if (_array.size() < kMinArraySize) {
  15. return;
  16. }
  17. // The max size of this array is about 2 * 2 ^ log2(n) + 1.
  18. const auto size = 2 * std::pow(
  19. 2.,
  20. std::floor((std::log(_array.size()) / std::log(2.)) + 1));
  21. _heap.resize(int(size));
  22. build(1, 0, _array.size());
  23. }
  24. void SegmentTree::build(ChartValue v, int from, int size) {
  25. _heap[v].from = from;
  26. _heap[v].to = (from + size - 1);
  27. if (size == 1) {
  28. _heap[v].sum = _array[from];
  29. _heap[v].max = _array[from];
  30. _heap[v].min = _array[from];
  31. } else {
  32. // Build children.
  33. build(2 * v, from, size / 2);
  34. build(2 * v + 1, from + size / 2, size - size / 2);
  35. _heap[v].sum = _heap[2 * v].sum + _heap[2 * v + 1].sum;
  36. // max = max of the children.
  37. _heap[v].max = std::max(_heap[2 * v].max, _heap[2 * v + 1].max);
  38. _heap[v].min = std::min(_heap[2 * v].min, _heap[2 * v + 1].min);
  39. }
  40. }
  41. ChartValue SegmentTree::rMaxQ(int from, int to) {
  42. if (_array.size() < kMinArraySize) {
  43. auto max = ChartValue(0);
  44. from = std::max(from, 0);
  45. to = std::min(to, int(_array.size() - 1));
  46. for (auto i = from; i <= to; i++) {
  47. max = std::max(max, _array[i]);
  48. }
  49. return max;
  50. }
  51. return rMaxQ(1, from, to);
  52. }
  53. ChartValue SegmentTree::rMaxQ(ChartValue v, int from, int to) {
  54. const auto &n = _heap[v];
  55. // If you did a range update that contained this node,
  56. // you can infer the Min value without going down the tree.
  57. if (n.pendingVal && contains(n.from, n.to, from, to)) {
  58. return n.pendingVal.value;
  59. }
  60. if (contains(from, to, n.from, n.to)) {
  61. return _heap[v].max;
  62. }
  63. if (intersects(from, to, n.from, n.to)) {
  64. propagate(v);
  65. const auto leftMin = rMaxQ(2 * v, from, to);
  66. const auto rightMin = rMaxQ(2 * v + 1, from, to);
  67. return std::max(leftMin, rightMin);
  68. }
  69. return 0;
  70. }
  71. ChartValue SegmentTree::rMinQ(int from, int to) {
  72. if (_array.size() < kMinArraySize) {
  73. auto min = std::numeric_limits<ChartValue>::max();
  74. from = std::max(from, 0);
  75. to = std::min(to, int(_array.size() - 1));
  76. for (auto i = from; i <= to; i++) {
  77. min = std::min(min, _array[i]);
  78. }
  79. return min;
  80. }
  81. return rMinQ(1, from, to);
  82. }
  83. ChartValue SegmentTree::rMinQ(ChartValue v, int from, int to) {
  84. const auto &n = _heap[v];
  85. // If you did a range update that contained this node,
  86. // you can infer the Min value without going down the tree.
  87. if (n.pendingVal && contains(n.from, n.to, from, to)) {
  88. return n.pendingVal.value;
  89. }
  90. if (contains(from, to, n.from, n.to)) {
  91. return _heap[v].min;
  92. }
  93. if (intersects(from, to, n.from, n.to)) {
  94. propagate(v);
  95. const auto leftMin = rMinQ(2 * v, from, to);
  96. const auto rightMin = rMinQ(2 * v + 1, from, to);
  97. return std::min(leftMin, rightMin);
  98. }
  99. return std::numeric_limits<ChartValue>::max();
  100. }
  101. void SegmentTree::propagate(ChartValue v) {
  102. auto &n = _heap[v];
  103. if (n.pendingVal) {
  104. const auto value = n.pendingVal.value;
  105. n.pendingVal = {};
  106. change(_heap[2 * v], value);
  107. change(_heap[2 * v + 1], value);
  108. }
  109. }
  110. void SegmentTree::change(SegmentTree::Node &n, ChartValue value) {
  111. n.pendingVal = { value, true };
  112. n.sum = n.size() * value;
  113. n.max = value;
  114. n.min = value;
  115. _array[n.from] = value;
  116. }
  117. bool SegmentTree::contains(int from1, int to1, int from2, int to2) const {
  118. return (from2 >= from1) && (to2 <= to1);
  119. }
  120. bool SegmentTree::intersects(int from1, int to1, int from2, int to2) const {
  121. return ((from1 <= from2) && (to1 >= from2)) // (.[..)..] or (.[...]..)
  122. || ((from1 >= from2) && (from1 <= to2)); // [.(..]..) or [..(..)..
  123. }
  124. } // namespace Statistic