Segment tree
Introduction: segment tree is a data structure commonly used in algorithm competition to maintain interval information.
The segment tree can realize single point modification, interval modification, interval query (interval summation, interval maximum and interval minimum) within the time complexity of O(logN).
The article only contains code and template examples. For specific learning, refer to the following links
Learning links: OI Wiki segment tree
Pre knowledge: tree array
Related knowledge: prefix sum, interval problem
code implementation
Basic structure of line segment tree
Sum of sum node intervals
lazy tag (delay tag)
Left and right endpoints of l r interval
The number of nodes in cnt interval can be replaced by r - l + 1
struct node { long long sum, lazy; int l, r, cnt; }; node tree[N * 4];
Build a tree
// Build a tree void built_tree(int now, int l, int r) { // First process the information that can be processed at the current point tree[now].l = l, tree[now].r = r; tree[now].cnt = r - l + 1; tree[now].lazy = 0; // There is only one element if (l == r) { tree[now].sum = num[l]; // num[r] = num[l]; return ; } // If there is not only one element, divide it into the left and right sections, and then go back to deal with your own sum int mid = (l + r) / 2; built_tree(now * 2, l, mid); built_tree(now * 2 + 1, mid + 1, r); // Update itself and values and abstract them into functions up_sum(now); }
// After the left and right intervals are processed, sum the values void up_sum(int now) { tree[now].sum = tree[now * 2].sum + tree[now * 2 + 1].sum; }
Interval query operation
// The interval query operation, the current point, solves the left interval of the interval and the right interval of the interval long long query(int now, int l, int r) { // If it is a fully contained relationship, you can return it directly if (tree[now].l >= l && tree[now].r <= r) { return tree[now].sum; } // If the relationship is not completely contained, it needs to be decomposed downward // Process the marking down before disassembly down_lazy(now); // The query is divided into two parts c++ int mid = (tree[now].l + tree[now].r) / 2; long long tsum = 0; // Divide from now, corresponding to the sum of both sides if (mid >= l) tsum += query(now * 2, l, r); // There's something on the left if (mid < r) tsum += query(now * 2 + 1, l, r); // There's something on the right return tsum; }
Interval modification
// Interval modification void modify(int now, int l, int r, int val) { // If it is a fully included relationship, you can modify it directly if (tree[now].l >= l && tree[now].r <= r) { tree[now].lazy += val; // Update lazy tag tree[now].sum += val * tree[now].cnt; // Update and values return ; } // If the relationship is not completely contained, it needs to be decomposed downward // Process the marking down before disassembly down_lazy(now); int mid = (tree[now].l + tree[now].r) / 2; if (mid >= l) modify(now * 2, l, r, val); if (mid < r) modify(now * 2 + 1, l, r, val); up_sum(now); }
Process lazy flag down (delay flag)
void down_lazy(int now) { // If the lazy of the current node is not 0 // The lazy mark began to sink if (tree[now].lazy != 0) { // Update lazy down tree[now * 2].lazy += tree[now].lazy; tree[now * 2 + 1].lazy += tree[now].lazy; // Update and values down tree[now * 2].sum += tree[now].lazy * tree[now * 2].cnt; tree[now * 2 + 1].sum += tree[now].lazy * tree[now * 2 + 1].cnt; tree[now].lazy = 0; } }
Line segment tree template question OJ - Online Judge (haizeix.com)
Title Description
Given a n n n-bit array and two operations:
Operation 1: add a value to all the numbers of an interval in the array
Operation 2: query the sum of all numbers in an interval in the array
input
Enter two integers on the first line n , m ( 1 ≤ n ≤ 10000 , 3 ≤ m ≤ 100000 ) n,m(1≤n≤10000,3≤m≤100000) n. M (1 ≤ n ≤ 10000, 3 ≤ m ≤ 100000) represents the array size and operands respectively.
The second line contains n n n integers representing the corresponding numbers in the array. The number size will not exceed i n t int int indicates the range.
next m m m lines, three or four integers per line a , b , c , d ( a ∈ [ 1 , 2 ] ) a,b,c,d(a∈[1,2]) a,b,c,d(a∈[1,2])
- When a = 1 a=1 When a=1 , enter next b , c , d b,c,d b. C, D, for the array [ b , c ] [b,c] Numbers in [b,c] interval plus d , ( 1 ≤ b , c ≤ n , d i s i n t ) d,(1≤b,c≤n, d is int) d. (1 ≤ b,c ≤ n,disint), when b > c b>c b> C, do not do any operation.
- When a = 2 a=2 When a=2, enter next b , c b,c b. C. input representative query [ b , c ] [b,c] Sum value in [b,c] interval ( 1 ≤ b , c ≤ n ) (1≤b,c≤n) (1 ≤ b,c ≤ n), when b > c b>c b> C, output 0 0 0.
output
For each a = 2 a=2 For the operation of a=2, the sum of the numbers in the query interval will be output, and the answer will not exceed 64 64 64 bit integer ( l o n g l o n g ) (long long) (long long long) represents the range of.
sample input
6 5
6 9 4 3 2 1
2 2 5
1 2 3 5
2 1 6
1 5 12 3
2 1 6
sample output
18
35
41
Main function code
int main() { cin >> n >> m; // Number of n elements, m operand for (int i = 1; i <= n; i++) { cin >> num[i]; } built_tree(1, 1, n); // The current node, the interval in which the tree is created // Get each operation for (int i = 0; i < m; i++) { int t; cin >> t; // Interval update operation if (t == 1) { int a, b, c; cin >> a >> b >> c; // Change to scanf, or it will timeout modify(1, a, b, c); // The interval update operation starts at point 1 of the tree root and adds c to the whole interval a to b // else interval query operation } else { int a, b; cin >> a >> b; cout << query(1, a, b) << endl; // Start from point 1 of the tree root and query the sum of intervals a to b } } return 0; }