SegmentTree.cpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. // segment tree for minimum and sum
  2. // root is in tree[1], children in tree[2i] and tree[2i+1]
  3. // all ranges in build/updates/queries are 0-based
  4. struct Node {
  5. int min, sum, up, size; // size of subtree
  6. void update(int x) {
  7. min += x;
  8. sum += x*size;
  9. up += x;
  10. }
  11. Node() {
  12. min = INF;
  13. up = sum = size = 0;
  14. }
  15. };
  16. Node *tree;
  17. int N;
  18. void compute(int v) { // update tree[v] from its children, v < N
  19. tree[v].min = min(tree[2*v].min, tree[2*v+1].min);
  20. tree[v].sum = tree[2*v].sum + tree[2*v+1].sum;
  21. }
  22. // read values[0..size-1]
  23. void build(int size, int values[]) {
  24. N = size > 1 ? 1 << ((int)log2(size-1)+1) : 1;
  25. tree = new Node[2*N];
  26. for(int i = 0; i < size; i++) { // leaves
  27. tree[N+i].min = tree[N+i].sum = values[i];
  28. tree[N+i].size = 1;
  29. }
  30. for(int i = N-1; i > 0; i--) { // interns
  31. compute(i);
  32. tree[i].size = tree[2*i].size + tree[2*i+1].size;
  33. }
  34. }
  35. void push(int v) {
  36. if(2*v < 2*N) // left subtree
  37. tree[2*v].update(tree[v].up);
  38. if(2*v+1 < 2*N) // right subtree
  39. tree[2*v+1].update(tree[v].up);
  40. tree[v].up = 0;
  41. }
  42. // v: current vertex with corressponding range [left, right)
  43. // find mimimum and sum of the range [l, r)
  44. pair<int, int> query_aux(int v, int left, int right, int l, int r) {
  45. push(v);
  46. if(right <= l || r <= left) // outside
  47. return {INF, 0};
  48. if(l <= left && right <= r) // inside
  49. return {tree[v].min, tree[v].sum};
  50. int m = (left+right)/2;
  51. int lm, rm, ls, rs;
  52. tie(lm, ls) = query_aux(2*v, left, m, l, r); // left subtree
  53. tie(rm, rs) = query_aux(2*v+1, m, right, l, r); // right
  54. return {min(lm, rm), ls+rs};
  55. }
  56. pair<int, int> query(int l, int r) {
  57. return query_aux(1, 0, N, l, r);
  58. }
  59. // update element at index i with value x
  60. void update(int i, int x) {
  61. i+=N;
  62. // push path from 1 to i
  63. int po = N;
  64. for(int v = 1; v < i;) {
  65. push(v);
  66. v*=2;
  67. if(i & po)
  68. v++; // i on right
  69. po /= 2;
  70. }
  71. tree[i].min = tree[i].sum = x; // update el
  72. for(i /= 2; i > 0; i /= 2) // update all segments containing i
  73. compute(i);
  74. }
  75. // v: the current vertex with corressponding range in [left, right)
  76. // add value x for element in range [l, r)
  77. void update_range_aux(int v, int left, int right, int l, int r, int x) {
  78. push(v);
  79. if(right <= l || r <= left)
  80. return;
  81. if(l <= left && right <= r) {
  82. tree[v].update(x);
  83. return;
  84. }
  85. int m = (left+right)/2;
  86. update_range_aux(2*v, left, m, l, r, x);
  87. update_range_aux(2*v+1, m, right, l, r, x);
  88. compute(v);
  89. }
  90. // update [l,r)
  91. void update_range(int l, int r, int x) {
  92. update_range_aux(1, 0, N, l, r, x);
  93. }