C 如何使用延迟传播实现分段树?

C 如何使用延迟传播实现分段树?,c,algorithm,data-structures,tree,C,Algorithm,Data Structures,Tree,我在互联网上搜索了关于分段树的实现,但在延迟传播方面什么也没找到。以前有一些关于堆栈溢出的问题,但它们主要是解决SPOJ的一些特殊问题。虽然我认为这是用伪代码解释段树的最好方法,但我需要用延迟传播来实现它。我发现了以下链接: 除了上面的链接,一些博客也在那里,但它们都引用了同一个线程 例子 这个数据结构应用的一个例子是,假设我得到了一个从1到n的数字范围。现在我执行一些操作,比如将一些常量添加到特定范围,或者从特定范围减去一些常量。在执行操作后,我应该告诉给定数字中的最小值和最大值 一个明显的

我在互联网上搜索了关于分段树的实现,但在延迟传播方面什么也没找到。以前有一些关于堆栈溢出的问题,但它们主要是解决SPOJ的一些特殊问题。虽然我认为这是用伪代码解释段树的最好方法,但我需要用延迟传播来实现它。我发现了以下链接:

除了上面的链接,一些博客也在那里,但它们都引用了同一个线程

例子 这个数据结构应用的一个例子是,假设我得到了一个从1到n的数字范围。现在我执行一些操作,比如将一些常量添加到特定范围,或者从特定范围减去一些常量。在执行操作后,我应该告诉给定数字中的最小值和最大值

一个明显的解决方案是对给定范围内的每个数字逐个进行加减运算。但在没有大规模操作的情况下,这是不可行的

更好的方法是使用分段树和延迟传播技术。它说,与其对每个数字单独执行更新操作,不如跟踪所有操作,直到所有操作完成。然后,最后执行更新操作以获得范围内的最小和最大数量

实际数据示例

假设我给出了范围[1,10],这意味着数字是1,2,3,4,5,6,7,8,9,10。 现在假设我执行一个操作,将[3,6]范围内的数字减少4,那么现在的数字看起来像1,2,-1,0,1,2,7,8,9,10。 现在我执行另一个操作,将[5,9]范围内的数字增加1,因此数字现在看起来像1,2,-1,0,2,3,8,9,10,10

现在,如果我让你告诉我最大和最小的数字,那么答案将是:

Maximum = 10

Minimum = -1
这只是一个简单的例子。实际问题可能包含数千个这样的加法/减法运算。我希望现在已经清楚了

这是我到目前为止所理解的,但我想互联网上没有一个统一的链接可以更好地解释这个概念和实现

有人能给出一些很好的解释,包括段树中延迟传播的伪代码吗


谢谢。

懒惰传播几乎总是包含某种岗哨机制。您必须验证当前节点不需要传播,并且该检查应该简单快速。因此有两种可能性:

  • 牺牲一点内存来保存节点中的一个字段,这可以很容易地进行检查
  • 牺牲一点运行时间来检查节点是否已传播以及是否必须创建其子节点
  • 我坚持第一条。检查分段树中的节点是否应该有子节点非常简单(
    node->lower\u value!=node->upper\u value
    ),但您还必须检查这些子节点是否已经构建(
    node->left\u child,node->right\u child
    ),因此我引入了一个传播标志
    node->propagated

    typedef struct lazy_segment_node{
      int lower_value;
      int upper_value;
    
      struct lazy_segment_node * left_child;
      struct lazy_segment_node * right_child;
    
      unsigned char propagated;
    } lazy_segment_node;
    
    初始化 要初始化节点,我们调用
    initialize
    ,指针指向节点指针(或
    NULL
    )和所需的
    上限值
    /
    下限值

    lazy_segment_node * initialize(
        lazy_segment_node ** mem, 
        int lower_value, 
        int upper_value
    ){
      lazy_segment_node * tmp = NULL;
      if(mem != NULL)
        tmp = *mem;
      if(tmp == NULL)
        tmp = malloc(sizeof(lazy_segment_node));
      if(tmp == NULL)
        return NULL;
      tmp->lower_value = lower_value;
      tmp->upper_value = upper_value;
      tmp->propagated = 0;
      tmp->left_child = NULL;
      tmp->right_child = NULL;
      
      if(mem != NULL)
        *mem = tmp;
      return tmp;
    }
    
    通道 到目前为止,还没有做任何特别的工作。这与其他所有通用节点创建方法类似。但是,为了创建实际的子节点并设置传播标志,我们可以使用一个函数,该函数将返回同一节点上的指针,但在需要时传播它:

    lazy_segment_node * accessErr(lazy_segment_node* node, int * error){
      if(node == NULL){
        if(error != NULL)
          *error = 1;
        return NULL;
      }
      /* if the node has been propagated already return it */
      if(node->propagated)
        return node;
    
      /* the node doesn't need child nodes, set flag and return */      
      if(node->upper_value == node->lower_value){
        node->propagated = 1;
        return node;
      }
    
      /* skipping left and right child creation, see code below*/
      return node;
    }
    
    如您所见,传播的节点几乎会立即退出该函数。一个未传播的节点将首先检查它是否应该包含子节点,然后根据需要创建它们

    这实际上是懒惰的评估。直到需要时才创建子节点。请注意,
    accessErr
    还提供了一个额外的错误接口。如果您不需要它,请使用
    access

    lazy_segment_node * access(lazy_segment_node* node){
      return accessErr(node,NULL);
    }
    
    自由的 为了释放这些元素,可以使用通用节点释放算法:

    void free_lazy_segment_tree(lazy_segment_node * root){
      if(root == NULL)
        return;
      free_lazy_segment_tree(root->left_child);
      free_lazy_segment_tree(root->right_child);
      free(root);
    }
    
    完整示例 下面的示例将使用上述函数基于间隔[1,10]创建一个延迟计算的段树。您可以看到,在第一次初始化之后,
    test
    没有子节点。通过使用
    access
    可以实际生成这些子节点,并可以获取它们的值(如果这些子节点通过分段树的逻辑存在):

    代码
    #包括
    #包括
    typedef结构惰性_段_节点{
    int较低的_值;
    int上_值;
    无符号字符传播;
    结构惰性\u段\u节点*左\u子节点;
    结构惰性\u段\u节点*右\u子节点;
    }延迟段节点;
    惰性\u段\u节点*初始化(惰性\u段\u节点**mem,整数下限值,整数上限值){
    惰性_段_节点*tmp=NULL;
    if(mem!=NULL)
    tmp=*mem;
    if(tmp==NULL)
    tmp=malloc(sizeof(lazy_段_节点));
    if(tmp==NULL)
    返回NULL;
    tmp->lower_值=lower_值;
    tmp->上限值=上限值;
    tmp->传播=0;
    tmp->left_child=NULL;
    tmp->right\u child=NULL;
    if(mem!=NULL)
    *mem=tmp;
    返回tmp;
    }
    惰性\u段\u节点*访问错误(惰性\u段\u节点*节点,int*错误){
    if(node==NULL){
    if(错误!=NULL)
    *误差=1;
    返回NULL;
    }
    如果(节点->传播)
    返回节点;
    如果(节点->上限值==节点->下限值){
    节点->传播=1;
    返回节点;
    }
    节点->左\u子节点=初始化(空,节点->下\u值,(节点->下\u值+节点->上\u值)/2);
    if(node->left_child==NULL){
    if(错误!=NULL)
    *误差=2;
    返回NULL;
    }
    节点->右\u子节点=初始化(空,(节点->下\u值+节点->上\u值
    
    #include <stdlib.h>
    #include <stdio.h>
    
    typedef struct lazy_segment_node{
      int lower_value;
      int upper_value;
      
      unsigned char propagated;
      
      struct lazy_segment_node * left_child;
      struct lazy_segment_node * right_child;
    } lazy_segment_node;
    
    lazy_segment_node * initialize(lazy_segment_node ** mem, int lower_value, int upper_value){
      lazy_segment_node * tmp = NULL;
      if(mem != NULL)
        tmp = *mem;
      if(tmp == NULL)
        tmp = malloc(sizeof(lazy_segment_node));
      if(tmp == NULL)
        return NULL;
      tmp->lower_value = lower_value;
      tmp->upper_value = upper_value;
      tmp->propagated = 0;
      tmp->left_child = NULL;
      tmp->right_child = NULL;
      
      if(mem != NULL)
        *mem = tmp;
      return tmp;
    }
    
    lazy_segment_node * accessErr(lazy_segment_node* node, int * error){
      if(node == NULL){
        if(error != NULL)
          *error = 1;
        return NULL;
      }
      if(node->propagated)
        return node;
      
      if(node->upper_value == node->lower_value){
        node->propagated = 1;
        return node;
      }
      node->left_child = initialize(NULL,node->lower_value,(node->lower_value + node->upper_value)/2);
      if(node->left_child == NULL){
        if(error != NULL)
          *error = 2;
        return NULL;
      }
      
      node->right_child = initialize(NULL,(node->lower_value + node->upper_value)/2 + 1,node->upper_value);
      if(node->right_child == NULL){
        free(node->left_child);
        if(error != NULL)
          *error = 3;
        return NULL;
      }  
      node->propagated = 1;
      return node;
    }
    
    lazy_segment_node * access(lazy_segment_node* node){
      return accessErr(node,NULL);
    }
    
    void free_lazy_segment_tree(lazy_segment_node * root){
      if(root == NULL)
        return;
      free_lazy_segment_tree(root->left_child);
      free_lazy_segment_tree(root->right_child);
      free(root);
    }
    
    int main(){
      lazy_segment_node * test = NULL;
      initialize(&test,1,10);
      printf("Lazy evaluation test\n");
      printf("test->lower_value: %i\n",test->lower_value);
      printf("test->upper_value: %i\n",test->upper_value);
      
      printf("\nNode not propagated\n");
      printf("test->left_child: %p\n",test->left_child);
      printf("test->right_child: %p\n",test->right_child);
      
      printf("\nNode propagated with access:\n");
      printf("access(test)->left_child: %p\n",access(test)->left_child);
      printf("access(test)->right_child: %p\n",access(test)->right_child);
      
      printf("\nNode propagated with access, but subchilds are not:\n");
      printf("access(test)->left_child->left_child: %p\n",access(test)->left_child->left_child);
      printf("access(test)->left_child->right_child: %p\n",access(test)->left_child->right_child);
      
      printf("\nCan use access on subchilds:\n");
      printf("access(test->left_child)->left_child: %p\n",access(test->left_child)->left_child);
      printf("access(test->left_child)->right_child: %p\n",access(test->left_child)->right_child);
      
      printf("\nIt's possible to chain:\n");
      printf("access(access(access(test)->right_child)->right_child)->lower_value: %i\n",access(access(access(test)->right_child)->right_child)->lower_value);
      printf("access(access(access(test)->right_child)->right_child)->upper_value: %i\n",access(access(access(test)->right_child)->right_child)->upper_value);
      
      free_lazy_segment_tree(test);
      
      return 0;
    }
    
    Lazy evaluation test test->lower_value: 1 test->upper_value: 10 Node not propagated test->left_child: (nil) test->right_child: (nil) Node propagated with access: access(test)->left_child: 0x948e020 access(test)->right_child: 0x948e038 Node propagated with access, but subchilds are not: access(test)->left_child->left_child: (nil) access(test)->left_child->right_child: (nil) Can use access on subchilds: access(test->left_child)->left_child: 0x948e050 access(test->left_child)->right_child: 0x948e068 It's possible to chain: access(access(access(test)->right_child)->right_child)->lower_value: 9 access(access(access(test)->right_child)->right_child)->upper_value: 10
    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <string>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <utility>
    #include <stack>
    #include <deque>
    #include <queue>
    #include <fstream>
    #include <functional>
    #include <numeric>
    
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cassert>
    
    #ifdef _WIN32 || _WIN64
    #define getc_unlocked _fgetc_nolock
    #endif
    
    using namespace std;
    
    const int MAX_RANGE = 1000000;
    const int NIL = -(1 << 29);
    int data[MAX_RANGE] = {0};
    int min_tree[3 * MAX_RANGE + 1];
    int max_tree[3 * MAX_RANGE + 1];
    int added_to_interval[3 * MAX_RANGE + 1];
    
    struct node {
        int max_value;
        int min_value;
        int added;
        node *left;
        node *right;
    };
    
    node* build_tree(int l, int r, int values[]) {
        node *root = new node;
        root->added = 0;
        if (l > r) {
            return NULL;
        }
        else if (l == r) {
            root->max_value = l + 1; // or values[l]
            root->min_value = l + 1; // or values[l]
            root->added = 0;
            root->left = NULL;
            root->right = NULL;
            return root;
        }
        else {  
            root->left = build_tree(l, (l + r) / 2, values);
            root->right = build_tree((l + r) / 2 + 1, r, values);
            root->max_value = max(root->left->max_value, root->right->max_value);
            root->min_value = min(root->left->min_value, root->right->min_value);
            root->added = 0;
            return root;
        }
    }
    
    node* build_tree(int l, int r) {
        node *root = new node;
        root->added = 0;
        if (l > r) {
            return NULL;
        }
        else if (l == r) {
            root->max_value = l + 1; // or values[l]
            root->min_value = l + 1; // or values[l]
            root->added = 0;
            root->left = NULL;
            root->right = NULL;
            return root;
        }
        else {  
            root->left = build_tree(l, (l + r) / 2);
            root->right = build_tree((l + r) / 2 + 1, r);
            root->max_value = max(root->left->max_value, root->right->max_value);
            root->min_value = min(root->left->min_value, root->right->min_value);
            root->added = 0;
            return root;
        }
    }
    
    void update_tree(node* root, int begin, int end, int i, int j, int amount) {
        // out of range
        if (begin > end || begin > j || end < i) {
            return;
        }
        // in update range (i, j)
        else if (i <= begin && end <= j) {
            root->max_value += amount;
            root->min_value += amount;
            root->added += amount;
        }
        else {
            if (root->left == NULL && root->right == NULL) {
                root->max_value = root->max_value + root->added;
                root->min_value = root->min_value + root->added;
            }
            else if (root->right != NULL && root->left == NULL) {
                update_tree(root->right, (begin + end) / 2 + 1, end, i, j, amount);
                root->max_value = root->right->max_value + root->added;
                root->min_value = root->right->min_value + root->added;
            }
            else if (root->left != NULL && root->right == NULL) {
                update_tree(root->left, begin, (begin + end) / 2, i, j, amount);
                root->max_value = root->left->max_value + root->added;
                root->min_value = root->left->min_value + root->added;
            }
            else {
                update_tree(root->right, (begin + end) / 2 + 1, end, i, j, amount);
                update_tree(root->left, begin, (begin + end) / 2, i, j, amount);
                root->max_value = max(root->left->max_value, root->right->max_value) + root->added;
                root->min_value = min(root->left->min_value, root->right->min_value) + root->added;
            }
        }
    }
    
    void print_tree(node* root) {
        if (root != NULL) {
            print_tree(root->left);
            cout << "\t(max, min): " << root->max_value << ", " << root->min_value << endl;
            print_tree(root->right);
        }
    }
    
    void clean_up(node*& root) {
        if (root != NULL) {
            clean_up(root->left);
            clean_up(root->right);
            delete root;
            root = NULL;
        }
    }
    
    void update_bruteforce(int x, int y, int z, int &smallest, int &largest, int data[], int n) {
        for (int i = x; i <= y; ++i) {
            data[i] += z;       
        }
    
        // update min/max
        smallest = data[0];
        largest = data[0];
        for (int i = 0; i < n; ++i) {
            if (data[i] < smallest) {
                smallest = data[i];
            }
    
            if (data[i] > largest) {
                largest = data[i];
            }
        }
    }
    
    void build_tree_as_array(int position, int left, int right) {
        if (left > right) {
            return;
        }
        else if (left == right) {
            max_tree[position] = left + 1;
            min_tree[position] = left + 1;
            added_to_interval[position] = 0;
            return;
        }
        else {
            build_tree_as_array(position * 2, left, (left + right) / 2);
            build_tree_as_array(position * 2 + 1, (left + right) / 2 + 1, right);
            max_tree[position] = max(max_tree[position * 2], max_tree[position * 2 + 1]);
            min_tree[position] = min(min_tree[position * 2], min_tree[position * 2 + 1]);
        }
    }
    
    void update_tree_as_array(int position, int b, int e, int i, int j, int value) {
        if (b > e || b > j || e < i) {
            return;
        }
        else if (i <= b && e <= j) {
            max_tree[position] += value;
            min_tree[position] += value;
            added_to_interval[position] += value;
            return;
        }
        else {
            int left_branch = 2 * position;
            int right_branch = 2 * position + 1;
            // make sure the array is ok
            if (left_branch >= 2 * MAX_RANGE + 1 || right_branch >= 2 * MAX_RANGE + 1) {
                max_tree[position] = max_tree[position] + added_to_interval[position];
                min_tree[position] = min_tree[position] + added_to_interval[position];
                return;
            }
            else if (max_tree[left_branch] == NIL && max_tree[right_branch] == NIL) {
                max_tree[position] = max_tree[position] + added_to_interval[position];
                min_tree[position] = min_tree[position] + added_to_interval[position];
                return;
            }
            else if (max_tree[left_branch] != NIL && max_tree[right_branch] == NIL) {
                update_tree_as_array(left_branch, b , (b + e) / 2 , i, j, value);
                max_tree[position] = max_tree[left_branch] + added_to_interval[position];
                min_tree[position] = min_tree[left_branch] + added_to_interval[position];
            }
            else if (max_tree[right_branch] != NIL && max_tree[left_branch] == NIL) {
                update_tree_as_array(right_branch, (b + e) / 2 + 1 , e , i, j, value);
                max_tree[position] = max_tree[right_branch] + added_to_interval[position];
                min_tree[position] = min_tree[right_branch] + added_to_interval[position];
            }
            else {
                update_tree_as_array(left_branch, b, (b + e) / 2 , i, j, value);
                update_tree_as_array(right_branch, (b + e) / 2 + 1 , e , i, j, value);
                max_tree[position] = max(max_tree[position * 2], max_tree[position * 2 + 1]) + added_to_interval[position]; 
                min_tree[position] = min(min_tree[position * 2], min_tree[position * 2 + 1]) + added_to_interval[position];
            }
        }
    }
    
    void show_data(int data[], int n) {
        cout << "[current data]\n";
        for (int i = 0; i < n; ++i) {
            cout << data[i] << ", ";
        }
        cout << endl;
    }
    
    inline void input(int* n) {
        char c = 0;
        while (c < 33) {
            c = getc_unlocked(stdin);
        }
    
        *n = 0;
        while (c > 33) {
            *n = (*n * 10) + c - '0';
            c = getc_unlocked(stdin);
        }
    }
    
    void handle_special_case(int m) {
        int type;
        int x;
        int y;
        int added_amount;
        for (int i = 0; i < m; ++i) {
            input(&type);
            input(&x);
            input(&y);
            input(&added_amount);
        }
        printf("0\n");
    }
    
    void find_largest_range_use_tree() {
        int n;
        int m;
        int type;
        int x;
        int y;
        int added_amount;
    
        input(&n);
        input(&m);
    
        if (n == 1) {
            handle_special_case(m);
            return;
        }
    
        node *root = build_tree(0, n - 1);
        for (int i = 0; i < m; ++i) {
            input(&type);
            input(&x);
            input(&y);
            input(&added_amount);
            if (type == 1) {    
                added_amount *= 1;
            }
            else {
                added_amount *= -1;
            }
    
            update_tree(root, 0, n - 1, x - 1, y - 1, added_amount);
        }
    
        printf("%d\n", root->max_value - root->min_value);
    }
    
    void find_largest_range_use_array() {
        int n;
        int m;
        int type;
        int x;
        int y;
        int added_amount;
    
        input(&n);
        input(&m);
    
        if (n == 1) {
            handle_special_case(m);
            return;
        }
    
        memset(min_tree, NIL, 3 * sizeof(int) * n + 1);
        memset(max_tree, NIL, 3 * sizeof(int) * n + 1);
        memset(added_to_interval, 0, 3 * sizeof(int) * n + 1);
        build_tree_as_array(1, 0, n - 1);
    
        for (int i = 0; i < m; ++i) {
            input(&type);
            input(&x);
            input(&y);
            input(&added_amount);
            if (type == 1) {    
                added_amount *= 1;
            }
            else {
                added_amount *= -1;
            }
    
            update_tree_as_array(1, 0, n - 1, x - 1, y - 1, added_amount);
        }
    
        printf("%d\n", max_tree[1] - min_tree[1]);
    }
    
    void update_slow(int x, int y, int value) {
        for (int i = x - 1; i < y; ++i) {
            data[i] += value;
        }
    }
    
    void find_largest_range_use_common_sense() {
        int n;
        int m;
        int type;
        int x;
        int y;
        int added_amount;
    
        input(&n);
        input(&m);
    
        if (n == 1) {
            handle_special_case(m);
            return;
        }
    
        memset(data, 0, sizeof(int) * n);
        for (int i = 0; i < m; ++i) {
            input(&type);
            input(&x);
            input(&y);
            input(&added_amount);
    
            if (type == 1) {    
                added_amount *= 1;
            }
            else {
                added_amount *= -1;
            }
    
            update_slow(x, y, added_amount);
        }
    
         // update min/max
        int smallest = data[0] + 1;
        int largest = data[0] + 1;
        for (int i = 1; i < n; ++i) {
            if (data[i] + i + 1 < smallest) {
                smallest = data[i] + i + 1;
            }
    
            if (data[i] + i + 1 > largest) {
                largest = data[i] + i + 1;
            }
        }
    
        printf("%d\n", largest - smallest); 
    }
    
    void inout_range_of_data() {
        int test_cases;
        input(&test_cases);
    
        while (test_cases--) {
            find_largest_range_use_common_sense();
        }
    }
    
    namespace unit_test {
        void test_build_tree() {
            for (int i = 0; i < MAX_RANGE; ++i) {
                data[i] = i + 1;
            }
    
            node *root = build_tree(0, MAX_RANGE - 1, data);
            print_tree(root);
        }
    
        void test_against_brute_force() {
              // arrange
            int number_of_operations = 100;
            for (int i = 0; i < MAX_RANGE; ++i) {
                data[i] = i + 1;
            }
    
            node *root = build_tree(0, MAX_RANGE - 1, data);
    
            // print_tree(root);
            // act
            int operation;
            int x;
            int y;
            int added_amount;
            int smallest = 1;
            int largest = MAX_RANGE;
    
            // assert
            while (number_of_operations--) {
                operation = rand() % 2; 
                x = 1 + rand() % MAX_RANGE;
                y = x + (rand() % (MAX_RANGE - x + 1));
                added_amount = 1 + rand() % MAX_RANGE;
                // cin >> operation >> x >> y >> added_amount;
                if (operation == 1) {
                    added_amount *= 1;
                }
                else {
                    added_amount *= -1;    
                }
    
                update_bruteforce(x - 1, y - 1, added_amount, smallest, largest, data, MAX_RANGE);
                update_tree(root, 0, MAX_RANGE - 1, x - 1, y - 1, added_amount);
                assert(largest == root->max_value);
                assert(smallest == root->min_value);
                for (int i = 0; i < MAX_RANGE; ++i) {
                    cout << data[i] << ", ";
                }
                cout << endl << endl;
                cout << "correct:\n";
                cout << "\t largest = " << largest << endl;
                cout << "\t smallest = " << smallest << endl;
                cout << "testing:\n";
                cout << "\t largest = " << root->max_value << endl;
                cout << "\t smallest = " << root->min_value << endl;
                cout << "testing:\n";
                cout << "\n------------------------------------------------------------\n";
                cout << "final result: " << largest - smallest << endl;
                cin.get();
            }
    
            clean_up(root);
        }
    
        void test_automation() {
              // arrange
            int test_cases;
            int number_of_operations = 100;
            int n;
    
    
            test_cases = 10000;
            for (int i = 0; i < test_cases; ++i) {
                n = i + 1;
    
                int operation;
                int x;
                int y;
                int added_amount;
                int smallest = 1;
                int largest = n;
    
    
                // initialize data for brute-force
                for (int i = 0; i < n; ++i) {
                    data[i] = i + 1;
                }
    
                // build tree   
                node *root = build_tree(0, n - 1, data);
                for (int i = 0; i < number_of_operations; ++i) {
                    operation = rand() % 2; 
                    x = 1 + rand() % n;
                    y = x + (rand() % (n - x + 1));
                    added_amount = 1 + rand() % n;
    
                    if (operation == 1) {
                        added_amount *= 1;
                    }
                    else {
                        added_amount *= -1;    
                    }
    
                    update_bruteforce(x - 1, y - 1, added_amount, smallest, largest, data, n);
                    update_tree(root, 0, n - 1, x - 1, y - 1, added_amount);
                    assert(largest == root->max_value);
                    assert(smallest == root->min_value);
    
                    cout << endl << endl;
                    cout << "For n = " << n << endl;
                    cout << ", where data is : \n";
                    for (int i = 0; i < n; ++i) {
                        cout << data[i] << ", ";
                    }
                    cout << endl;
                    cout << " and query is " << x - 1 << ", " << y - 1 << ", " << added_amount << endl;
                    cout << "correct:\n";
                    cout << "\t largest = " << largest << endl;
                    cout << "\t smallest = " << smallest << endl;
                    cout << "testing:\n";
                    cout << "\t largest = " << root->max_value << endl;
                    cout << "\t smallest = " << root->min_value << endl;
                    cout << "\n------------------------------------------------------------\n";
                    cout << "final result: " << largest - smallest << endl;
                }
    
                clean_up(root);
            }
    
            cout << "DONE............\n";
        }
    
        void test_tree_as_array() {
              // arrange
            int test_cases;
            int number_of_operations = 100;
            int n;
            test_cases = 1000;
            for (int i = 0; i < test_cases; ++i) {
                n = MAX_RANGE;
                memset(min_tree, NIL, sizeof(min_tree));
                memset(max_tree, NIL, sizeof(max_tree));
                memset(added_to_interval, 0, sizeof(added_to_interval));
                memset(data, 0, sizeof(data));
    
                int operation;
                int x;
                int y;
                int added_amount;
                int smallest = 1;
                int largest = n;
    
    
                // initialize data for brute-force
                for (int i = 0; i < n; ++i) {
                    data[i] = i + 1;
                }
    
                // build tree using array
                build_tree_as_array(1, 0, n - 1);
                for (int i = 0; i < number_of_operations; ++i) {
                    operation = rand() % 2; 
                    x = 1 + rand() % n;
                    y = x + (rand() % (n - x + 1));
                    added_amount = 1 + rand() % n;
    
                    if (operation == 1) {
                        added_amount *= 1;
                    }
                    else {
                        added_amount *= -1;    
                    }
    
                    update_bruteforce(x - 1, y - 1, added_amount, smallest, largest, data, n);
                    update_tree_as_array(1, 0, n - 1, x - 1, y - 1, added_amount);
                    //assert(max_tree[1] == largest);
                    //assert(min_tree[1] == smallest);
    
                    cout << endl << endl;
                    cout << "For n = " << n << endl;
                    // show_data(data, n);
                    cout << endl;
                    cout << " and query is " << x - 1 << ", " << y - 1 << ", " << added_amount << endl;
                    cout << "correct:\n";
                    cout << "\t largest = " << largest << endl;
                    cout << "\t smallest = " << smallest << endl;
                    cout << "testing:\n";
                    cout << "\t largest = " << max_tree[1] << endl;
                    cout << "\t smallest = " << min_tree[1] << endl;
                    cout << "\n------------------------------------------------------------\n";
                    cout << "final result: " << largest - smallest << endl;
                    cin.get();
                }
            }
    
            cout << "DONE............\n";
        }
    }
    
    int main() {
        // unit_test::test_against_brute_force();
        // unit_test::test_automation();    
        // unit_test::test_tree_as_array();
        inout_range_of_data();
    
        return 0;
    }
    
    init(T, hi) // make a segment tree for the interval [0; 1,hi]
    split(T, x, d)  // given there exists some interval [e; lo,hi],
                    // in T where lo < x <= hi, replace this interval
                    // with 2 new ones [e; lo,x-1] and [d; x,hi];
                    // if x==lo, then replace with [e+d; lo,hi]
    
    split(T, lo, d); split(T, hi+1, -d);
    
    /**
     * In this code we have a very large array called arr, and very large set of operations
     * Operation #1: Increment the elements within range [i, j] with value val
     * Operation #2: Get max element within range [i, j]
     * Build tree: build_tree(1, 0, N-1)
     * Update tree: update_tree(1, 0, N-1, i, j, value)
     * Query tree: query_tree(1, 0, N-1, i, j)
     */
    
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    #include<string.h>
    #include<math.h> 
    
    #define N 20
    #define MAX (1+(1<<6)) // Why? :D
    #define inf 0x7fffffff
    
    int arr[N];
    int tree[MAX];
    int lazy[MAX];
    
    /**
     * Build and init tree
     */
    void build_tree(int node, int a, int b) {
        if(a > b) return; // Out of range
    
        if(a == b) { // Leaf node
                tree[node] = arr[a]; // Init value
            return;
        }
    
        build_tree(node*2, a, (a+b)/2); // Init left child
        build_tree(node*2+1, 1+(a+b)/2, b); // Init right child
    
        tree[node] = max(tree[node*2], tree[node*2+1]); // Init root value
    }
    
    /**
     * Increment elements within range [i, j] with value value
     */
    void update_tree(int node, int a, int b, int i, int j, int value) {
    
        if(lazy[node] != 0) { // This node needs to be updated
            tree[node] += lazy[node]; // Update it
    
            if(a != b) {
                lazy[node*2] += lazy[node]; // Mark child as lazy
                    lazy[node*2+1] += lazy[node]; // Mark child as lazy
            }
    
            lazy[node] = 0; // Reset it
        }
    
        if(a > b || a > j || b < i) // Current segment is not within range [i, j]
            return;
    
        if(a >= i && b <= j) { // Segment is fully within range
                tree[node] += value;
    
            if(a != b) { // Not leaf node
                lazy[node*2] += value;
                lazy[node*2+1] += value;
            }
    
                return;
        }
    
        update_tree(node*2, a, (a+b)/2, i, j, value); // Updating left child
        update_tree(1+node*2, 1+(a+b)/2, b, i, j, value); // Updating right child
    
        tree[node] = max(tree[node*2], tree[node*2+1]); // Updating root with max value
    }
    
    /**
     * Query tree to get max element value within range [i, j]
     */
    int query_tree(int node, int a, int b, int i, int j) {
    
        if(a > b || a > j || b < i) return -inf; // Out of range
    
        if(lazy[node] != 0) { // This node needs to be updated
            tree[node] += lazy[node]; // Update it
    
            if(a != b) {
                lazy[node*2] += lazy[node]; // Mark child as lazy
                lazy[node*2+1] += lazy[node]; // Mark child as lazy
            }
    
            lazy[node] = 0; // Reset it
        }
    
        if(a >= i && b <= j) // Current segment is totally within range [i, j]
            return tree[node];
    
        int q1 = query_tree(node*2, a, (a+b)/2, i, j); // Query left child
        int q2 = query_tree(1+node*2, 1+(a+b)/2, b, i, j); // Query right child
    
        int res = max(q1, q2); // Return final result
    
        return res;
    }
    
    int main() {
        for(int i = 0; i < N; i++) arr[i] = 1;
    
        build_tree(1, 0, N-1);
    
        memset(lazy, 0, sizeof lazy);
    
        update_tree(1, 0, N-1, 0, 6, 5); // Increment range [0, 6] by 5
        update_tree(1, 0, N-1, 7, 10, 12); // Incremenet range [7, 10] by 12
        update_tree(1, 0, N-1, 10, N-1, 100); // Increment range [10, N-1] by 100
    
        cout << query_tree(1, 0, N-1, 0, N-1) << endl; // Get max element in range [0, N-1]
    }