[advanced data structure] [algorithm notes] segment tree

Posted by fluteflute on Fri, 03 Dec 2021 19:00:07 +0100

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])

  1. 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.
  2. 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;
}

Topics: C++ Algorithm data structure