Learning note line segment tree

         Segment tree is a binary search tree, which is similar to interval tree. It divides an interval into some unit intervals, and each unit interval corresponds to a leaf node in the segment tree.
         For each non leaf node [a,b] in the segment tree, the interval represented by its left son is [a,(a+b)/2], and the interval represented by its right son is [(a+b)/2+1,b]. Therefore, the segment tree is a balanced binary tree, and the last number of child nodes is N, that is, the length of the whole segment interval.
         Using the segment tree, you can quickly find the number of occurrences of a node in several segments, with a time complexity of O(logN), while the unoptimized space complexity is 2N. Therefore, it is sometimes necessary to discretize and compress the space.

For any node i, the sequence number of its left son is 2*i, and the sequence number of its right son is 2*i+1. The reason why the space is 4N is to represent the array of full binary trees, that is, the nodes with sequence numbers of 9 ~ 15 also leave space for the left and right subtrees.

Create segment tree

void build(int node,int l,int r)
{
	if(l == r)
	{
		tree[node] = a[l];
		return;
	}
	int mid = (l+r)/2;
	build(node*2,l,mid);
	build(node*2+1,mid+1,r);
	tree[node] = tree[node*2] + tree[node*2 + 1];
}

Single point update

// Single point update, n is the update value, index is the update point, and lr is the update range
void update(int n,int index,int l,int r,int node)
{
	if(l==r)
	{
		tree[node] = n; // The update method can be changed freely
		return;
	}
	int mid = (l+r) / 2;
	// push_down(node,mid-l+1,r-mid); this sentence is required if there are both point updates and interval updates
	if(index <= mid)
	{
		update(n,index,l,mid,node*2);
	}
	else
	{
		update(n,index,mid+1,r,node*2+1);
	}
	tree[node] = tree[node*2] + tree[node*2 + 1];
}

Interval update

// For interval update, LR is the update range, LR is the segment tree range, and add is the update value
void update_range(int node,int l,int r,int L,int R,int add)
{
	if(l <= L && r >= R){
		lz[node] += 1LL*add;
		tree[node] += 1LL*(R - L + 1)*add; // Update mode
		return;
	}
	push_down(node,L,R);
	int mid = (L+R) / 2;
	if(mid >= l) update_range(node*2,l,r,L,mid,add);
	if(mid < r) update_range(node*2 + 1,l,r,mid+1,R,add);
	tree[node] = tree[node*2] + tree[node*2 + 1];
}

Interval search

// Interval search
LL query_range(int node,int L,int R,int l,int r)
{
	if(l <= L && r >= R) return tree[node];
	push_down(node,L,R);
	int mid = (L+R) / 2;
	LL sum = 0;
	if(mid >= l) sum += query_range(node*2,L,mid,l,r);
	if(mid < r) sum += query_range(node*2 + 1,mid+1,R,l,r);
	return sum;
}

Pushdown

void push_down(int node,int l,int r)
{
	if(lz[node]){
		int mid = (l+r) / 2;
		lz[node*2] += lz[node];
		lz[node*2 + 1] += lz[node];
		tree[node*2] += 1LL*(mid - l + 1)*lz[node];
		tree[node*2 + 1] += 1LL*(r - mid)*lz[node];
		lz[node] = 0;
	}
}

A Simple Problem with Integers

Time Limit: 5000MSMemory Limit: 131072K
Total Submissions: 197009Accepted: 60782
Case Time Limit: 2000MS

Description

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.

  Explanation:

There are an array A1~AN composed of N numbers,

Operation "c"   a   b   c ": add c to Aa~Ab respectively;

Operation "Q"   a   b ": find the sum of Aa~Ab;

Output the correct value for the summation operation; perform the correct modification for the modification operation;

analysis

  The first line contains two numbers   N   and   Q. 1 ≤   N,Q   ≤ 100000. If you use the prefix method to sum, you will definitely meet TLE. So this problem is to use the line segment tree... Just set the template directly

AC code

#include<iostream>
#include<string>
#include<stdio.h>
#define LL long long
#define MAX 1005000

#define N MAX
using namespace std;

LL tree[1005000]; // Segment tree
LL lz[1005000]; // Delay marking
LL a[1005000];
LL n,q;

void init()
{
	for(int i=0;i<N;++i)
	{
		tree[i] = lz[i] = 0;
	}

	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&a[i]);
	}
}

// Create segment tree
void build(int node,int l,int r)
{
	if(l == r)
	{
		tree[node] = a[l];
		return;
	}
	int mid = (l+r)/2;
	build(node*2,l,mid);
	build(node*2+1,mid+1,r);
	tree[node] = tree[node*2] + tree[node*2 + 1];
}

// Single point update, n is the update value, index is the update point, and lr is the update range
void update(int n,int index,int l,int r,int node)
{
	if(l==r)
	{
		tree[node] = n; // The update method can be changed freely
		return;
	}
	int mid = (l+r) / 2;
	// push_down(node,mid-l+1,r-mid); this sentence is required if there are both point updates and interval updates
	if(index <= mid)
	{
		update(n,index,l,mid,node*2);
	}
	else
	{
		update(n,index,mid+1,r,node*2+1);
	}
	tree[node] = tree[node*2] + tree[node*2 + 1];
}

void push_down(int node,int l,int r)
{
	if(lz[node]){
		int mid = (l+r) / 2;
		lz[node*2] += lz[node];
		lz[node*2 + 1] += lz[node];
		tree[node*2] += 1LL*(mid - l + 1)*lz[node];
		tree[node*2 + 1] += 1LL*(r - mid)*lz[node];
		lz[node] = 0;
	}
}

// For interval update, LR is the update range, LR is the segment tree range, and add is the update value
void update_range(int node,int l,int r,int L,int R,int add)
{
	if(l <= L && r >= R){
		lz[node] += 1LL*add;
		tree[node] += 1LL*(R - L + 1)*add; // Update mode
		return;
	}
	push_down(node,L,R);
	int mid = (L+R) / 2;
	if(mid >= l) update_range(node*2,l,r,L,mid,add);
	if(mid < r) update_range(node*2 + 1,l,r,mid+1,R,add);
	tree[node] = tree[node*2] + tree[node*2 + 1];
}

// Interval search
LL query_range(int node,int L,int R,int l,int r)
{
	if(l <= L && r >= R) return tree[node];
	push_down(node,L,R);
	int mid = (L+R) / 2;
	LL sum = 0;
	if(mid >= l) sum += query_range(node*2,L,mid,l,r);
	if(mid < r) sum += query_range(node*2 + 1,mid+1,R,l,r);
	return sum;
}
int main()
{

	scanf("%lld%lld",&n,&q);
	init();
	build(1,1,n);
	for(int i=1;i<=q;i++)
	{
		char ch;
		cin>>ch;
		if(ch=='Q')
		{
			LL a,b;
            scanf("%lld%lld",&a,&b);
			printf("%lld\n",query_range(1,1,n,a,b));
			// cin>>a>>b;
			// cout<<query_range(1,1,n,a,b)<<endl;

		}
		if(ch=='C')
		{
			LL a,b,c;
			//cin>>a>>b>>c;
            scanf("%lld%lld%lld",&a,&b,&c);
			update_range(1,a,b,1,n,c);
		}
	}
	return 0;
}

emmm leave several pits for later filling:

The meaning of lazy tag and time complexity analysis;

Supplement the application scope of segment tree, such as summation and maximum difference in interval;

Supplement practical examples, skillfully modify and use templates;

Tags: html5 Algorithm

Posted on Thu, 14 Oct 2021 15:40:28 -0400 by louie