Olivier Marty преди 8 години
родител
ревизия
7e9fc5d223
променени са 1 файла, в които са добавени 75 реда и са изтрити 96 реда
  1. 75 96
      code/SegmentTree.cpp

+ 75 - 96
code/SegmentTree.cpp

@@ -1,106 +1,85 @@
-const int MAXNUM = 1000;
-struct SegTreeNode
-{
-  int val;
-  int addMark;// label retardé
-} segTree[MAXNUM];
-
-/*
-arr: valeur des feuilles
-istart: indice début
-iend: indice end
-*/
-void build(int root, int arr[], int istart, int iend)
-{
-  segTree[root].addMark = 0;
-  if(istart == iend) // attend un feuille
-    segTree[root].val = arr[istart];
-  else
-  {
-    int mid = (istart + iend) / 2;
-    build(root*2+1, arr, istart, mid); // créé l'arbre gauche
-    build(root*2+2, arr, mid+1, iend); // créé l'arbre droit
-    // calcul le min des deux
-    segTree[root].val = min(segTree[root*2+1].val, segTree[root*2+2].val);
+// segment tree for minimum
+// root is in tree[1], children in tree[2i] and tree[2i+1]
+// all ranges in build/updates/queries are 0-based
+const int INFI=1000000000;
+struct Node {
+  int v; int up;
+  void update(int x) {
+    v += x;
+    up += x;
   }
-}
-/*
-pushDown le label retardé
-*/
-void pushDown(int root)
-{
-  if(segTree[root].addMark != 0)
-  {
-    segTree[root*2+1].addMark += segTree[root].addMark;
-    segTree[root*2+2].addMark += segTree[root].addMark;
-    segTree[root*2+1].val += segTree[root].addMark;
-    segTree[root*2+2].val += segTree[root].addMark;
-    segTree[root].addMark = 0;
+  Node() {
+    v = INFI;
+    up = 0;
   }
+};
+Node *tree;
+int N;
+// read values[0..size-1]
+void build(int size, int values[]) {
+  N = 1 << ((int)log2(size-1)+1);
+  tree = new Node[2*N];
+  for(int i = 0; i < size; i++) // leaves
+    tree[N+i].v = values[i];
+  for(int i = N-1; i > 0; i--) // interns
+    tree[i].v = min(tree[2*i].v, tree[2*i+1].v);
+}
+void push(int v) {
+  if(2*v < 2*N) // left subtree
+    tree[2*v].update(tree[v].up);
+  if(2*v+1 < 2*N) // right subtree
+    tree[2*v+1].update(tree[v].up);
+  tree[v].up = 0;
 }
-/*
-[nstart, nend]: intervale associé à root
-[qstart, qend]: intervale de la question
-*/
-int query(int root, int nstart, int nend, int qstart, int qend)
-{
-  // pas d'intersection
-  if(qstart > nend || qend < nstart)
-    return INFINITE;
-  // [nstart, nend] est inclu dans [qstart, qend]
-  if(qstart <= nstart && qend >= nend)
-    return segTree[root].val;
-  pushDown(root);
-  // min de la question sur les deux fils
-  int mid = (nstart + nend) / 2;
-  return min(query(root*2+1, nstart, mid, qstart, qend),
-           query(root*2+2, mid + 1, nend, qstart, qend));
-
+// v: current vertex with corressponding range [left, right)
+// find mimimum in the rangeg [l, r)
+int query_aux(int v, int left, int right, int l, int r) {
+  push(v);
+  if(right <= l || r <= left) // outside
+    return INFI;
+  if(l <= left && right <= r) // inside
+    return tree[v].v;
+  int m = (left+right)/2;
+  int left_min = query_aux(2*v, left, m, l, r); // left subtree
+  int right_min = query_aux(2*v+1, m, right, l, r); // right
+  return min(left_min, right_min);
 }
-
-/*
-change la valeur d'une feuille
-[nstart, nend]
-index: indice de la feuille dans arr
-addVal: différence à ajouter
-*/
-void updateOne(int root, int nstart, int nend, int index, int addVal)
-{
-  if(nstart == nend)
-  {
-      if(index == nstart) // feuille cherchée
-          segTree[root].val += addVal;
-      return;
+int query(int l, int r) {
+  return query_aux(1, 0, N, l, r);
+}
+// update element at index i with value x
+void update(int i, int x) {
+  i+=N;
+  // push path from 1 to i
+  int po = N;
+  for(int v = 1; v < i;) {
+    push(v);
+    if(i & po)
+	  v = 2*v + 1; // i on right
+    else
+	  v = 2*v; // left
+	po /= 2;
   }
-  int mid = (nstart + nend) / 2;
-  if(index <= mid) // à gauche
-      updateOne(root*2+1, nstart, mid, index, addVal);
-  else updateOne(root*2+2, mid+1, nend, index, addVal); // à droite
-  // prend le minimum
-  segTree[root].val = min(segTree[root*2+1].val, segTree[root*2+2].val);
+  tree[i].v = x; // update el
+  for(i /= 2; i > 0; i /= 2) // update all segments containing i
+    tree[i].v = min(tree[2*i].v, tree[2*i+1].v);
 }
-
-/*
-Met à jour un intervale
-[nstart, nend]: intervale du noeud
-[ustart, uend]: intervale à mettre à jour
-addVal: différence à ajouter
-*/
-void update(int root, int nstart, int nend, int ustart, int uend, int addVal)
-{
-  // pas d'intersection
-  if(ustart > nend || uend < nstart)
+// v: the current vertex with corressponding range in [left, right)
+// add value x for element in range [l, r)
+void update_range_aux(int v, int left, int right, int l, int r, int x) {
+  push(v);
+  if(right <= l || r <= left)
     return;
-  // inclu
-  if(ustart <= nstart && uend >= nend)
-  {
-    segTree[root].addMark += addVal;
-    segTree[root].val += addVal;
+  if(l <= left && right <= r) {
+    tree[v].update(x);
     return;
   }
-  pushDown(root);
-  int mid = (nstart + nend) / 2;
-  update(root*2+1, nstart, mid, ustart, uend, addVal);
-  update(root*2+2, mid+1, nend, ustart, uend, addVal);
-  segTree[root].val = min(segTree[root*2+1].val, segTree[root*2+2].val);
+  int m = (left+right)/2;
+  update_range_aux(2*v, left, m, l, r, x);
+  update_range_aux(2*v+1, m, right, l, r, x);
+  tree[v].v = min(tree[2*v].v, tree[2*v+1].v);
+}
+// update [l,r)
+void update_range(int l, int r, int x) {
+  update_range_aux(1, 0, N, l, r, x);
 }