如何实现具有延迟传播的分段树?

我在互联网上搜索了关于Segment树的实现但是在懒惰传播时没有发现任何东西。 之前有一些关于堆栈溢出的问题,但他们专注于解决SPOJ的一些特殊问题。 虽然我认为这是具有伪代码的分段树的最佳解释,但我需要使用延迟传播来实现它。 我发现以下链接:

http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor#Segment_Trees

除了上面的链接,一些博客也在那里,但他们都提供了相同的线程参考。

应用这种数据结构的一个例子就是说,我已经获得了从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 

这只是一个简单的例子。实际问题可能包含数千个这样的加法/减法操作。我希望现在很清楚。

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

任何人都可以给出一些很好的解释,包括在段树中延迟传播的伪代码吗?

谢谢。

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

  1. 牺牲一点内存来保存节点中的字段,这可以很容易地检查
  2. 牺牲一点运行时间来检查节点是否已被传播以及是否必须创建其子节点。

我坚持到第一个。 检查分段树中的节点是否应该具有子节点( node->lower_value != node->upper_value )非常简单,但您还必须检查这些子节点是否已构建( node->left_child, node->right_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; 

初始化

要初始化一个节点,我们使用指向节点指针(或NULL )和所需upper_value / lower_value的指针调用initialize

 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还提供了一个额外的错误接口。 如果您不需要它,请改用:

 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您实际生成了这些子节点并可以获取它们的值(如果这些子节点存在于分段树的逻辑中):

 #include  #include  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; } 

结果(ideone)

 懒惰的评估测试
 test-> lower_value:1
 test-> upper_value:10

节点未传播
 test-> left_child:(nil)
 test-> right_child :(无)

通过访问传播的节点:
 access(test) - > left_child:0x948e020
 access(test) - > right_child:0x948e038

节点通过访问传播,但子节点不是:
 access(test) - > left_child-> left_child:(nil)
 access(test) - > left_child-> right_child:(nil)

可以在子子上使用访问权限:
 access(test-> left_child) - > left_child:0x948e050
 access(test-> left_child) - > right_child:0x948e068

可以链接:
访问(访问(访问(测试) - > right_child) - > right_child) - > lower_value:9
访问(访问(访问(测试) - > right_child) - > right_child) - > upper_value:10 

如果有人在不使用结构的情况下寻找更简单的延迟传播代码:

(代码不言自明)

 /** * 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 #include using namespace std; #include #include #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] } 

请参阅此链接以获取更多解释段树和延迟传播

虽然我还没有成功解决它,但我相信这个问题比我们想象的容易得多。 您可能甚至不需要使用段树/间隔树…实际上,我尝试了两种方式来实现Segment Tree ,一种使用树结构,另一种使用数组,两种解决方案都快速获得了TLE。 我觉得可以用Greedy完成,但我还不确定。 无论如何,如果你想看看如何使用Segment Tree完成任务,请随时研究我的解决方案。 请注意, max_tree[1]min_tree[1]对应于max/min

 #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #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; } 

使段树变得懒惰似乎没有任何优势。 最终,您需要查看每个单位坡度段的末端以获得最小值和最大值。 所以你不妨热切地扩展它们。

相反,只需修改标准段树定义即可。 树中的间隔将各自存储一个额外的整数d ,因此我们将写入[d; lo,hi] [d; lo,hi] 。 该树具有以下操作:

 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] 

现在,在初始化之后,我们使用两个拆分操作处理向子区间[lo,hi]添加d

 split(T, lo, d); split(T, hi+1, -d); 

这里的想法是我们将d添加到位置lo和右边的所有内容并再次将其减去hi+1和right。

构造树之后,在叶子上进行单个从左到右的传递,我们可以找到整数单位斜率段末端的值。 这就是我们计算最小值和最大值所需的全部内容。 更正式地说,如果树的叶间隔是[d_i; lo_i,hi_i] [d_i; lo_i,hi_i]i=1..n按从左到右的顺序,然后我们想要计算运行差D_i = sum{i=1..n} d_i然后L_i = lo_i + D_iH_i = hi_i + D_i 。 在这个例子中,我们从[0; 1,10] [0; 1,10]然后在4处用d = -4和7分裂,其中d = + 4,得到[0; 1,2] [-4; 3,6] [4; 7,10] [0; 1,2] [-4; 3,6] [4; 7,10] [0; 1,2] [-4; 3,6] [4; 7,10] 。 然后L = [1,-1,7]并且H = [2, 2, 10] L = [1,-1,7] H = [2, 2, 10] 。 所以min是-1而max是10.这是一个简单的例子,但它一般都可以工作。

运行时间将是O(min(k log N,k ^ 2))其中N是最大初始范围值(在该示例中为10)并且k是所应用的操作的数量。 如果您在分割顺序方面运气非常差,则会发生k ^ 2情况。 如果随机化操作列表,预期时间将为O(k min(log N,log k))。

如果您有兴趣,我可以为您编写代码。 但如果没有兴趣,我不会。

这是链接。 它具有延迟传播的分段树的实现和解释。 虽然代码是用Java编写的,但它并不重要,因为只有两个函数’update’和’query’,它们都是基于数组的。 因此,这些函数也可以在C和C ++中使用,也无需任何修改。

http://isharemylearning.blogspot.in/2012/08/lazy-propagation-in-segment-tree.html