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: 5000MS | Memory Limit: 131072K | |
Total Submissions: 197009 | Accepted: 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;