Statement :
Only one picture reproduced in http://www.cnblogs.com/shuaiwhu/archive/2012/04/22/2464583.html, oneself painting too troublesome ... That blog is also very good explanation, but he used a pointer to define the line segment tree, and I used the structure, and he spoke of the line segment tree more advanced operations, if the line tree of the primary operation does not understand, please continue to read
As a very common data structure, segment tree is widely used in Noip and Noi, so the segment tree is briefly explained here.
The segment tree supports summation of a sequence, single-point modification, maximum (max, min), Interval modification (requires lazy marking, not explained). These kinds of operations, time complexity is (LOGN) level, is a very good data structure. Therefore, it has been widely used.
definition : As the name implies, it is a tree structure, but each paragraph is not a point of the usual learning of a point of the tree, but a line of lines, each segment contains a number of values, the most important of which is the start and end points are recorded as L,r that is the left and right endpoints.
So how do you divide the line tree? We use the idea of two points, that is, each time we take a half, then the next operation, so that the ease of operation and the complexity of time. Because the segment tree is derived from two points, the segment tree is a binary tree. This also facilitates the search for the son. Below is a diagram of the line tree, which is useful for understanding:
achievements : Only know the model is not enough, the process of achievement is the key line tree (build (1,1,n)) from the beginning, the left is 1, the right side is n
Bit operation i<<1 equivalent to I/2 (i<<1) | | | is equivalent to i/2+1 acceleration ...
InlinevoidUpdateinti) Update the values maintained by the I node (SUM, Max ...) ) {Node[i].sum=node[i<<1].sum+node[(i<<1)|1].sum; Node[i].maxx=max (node[i<<1].maxx,node[(i<<1)|1].maxx); }inlinevoidBuildintIintLintR//Inline or acceleration{NODE[I].L=l;node[i].r=r;//the left and right endpoints are current recursion to the L and R if(L==R) {//if l==r, then the current tree node is a real point .NODE[I].MAXX=A[L];//The maximum value is the value of itselfNODE[I].SUM=A[L];//and the value of the interval is itself. return; } intMid= (L+R)/2;//because it's a two-prong tree, the midpoint is the split point.Build (i<<1, L,mid);//according to the knowledge of the binary tree, the left son is i/2 right son is i/2+1Build ((i<<1)|1, mid+1, R); Update (i);}
Sequence sum: This is a typical algorithm of line-segment tree, and many other applications are converted from it.
To sum up we define a function sum (int i, int l, int r) i is the starting tree node, we default to 1. L is the starting point of the interval, the label of which is the label in the sequence, andR is the rest of the end point with l. Post code:
InlineintSumintIintLintR//Inline is also accelerating{ if(node[i].l==l&&node[i].r==R)returnNode[i].sum;//if the left and right intervals of the tree node are the same as the lookup interval, returns the sum maintained intMid= (NODE[I].L+NODE[I].R)/2;//determine the midpoint of the tree node to determine whether to continue looking for the left son or the right son if(R<=mid)returnSUM (i<<1, l,r);//if the right end of the search interval is less than the midpoint, the interval is completely contained in the left son Else if(L>mid)returnSum ((i<<1)|1, l,r);//the left end is greater than the midpoint, find the right son Else returnSUM (i<<1, L,mid) +sum ((i<<1)|1, mid+1, R)//If you cross the midpoint, find the left son L to mid, and the right son's mid+1 to R and return the value}
interval to calculate the maximum and interval sum is roughly the same, see for yourself
InlineintMax (intIintLintR) { if(node[i].l==l&&node[i].r==R)returnNode[i].maxx; intMid= (NODE[I].L+NODE[I].R)/2; if(R<=mid)returnMax (i<<1, L,r); Else if(L>mid)returnMax ((i<<1)|1, L,r); Else returnMax (Max (i<<1, L,mid), Max ((i<<1)|1, mid+1, R));}
single-point update : Different from the interval, but the basic idea is the same.
InlinevoidAddintIintKintV//The currently calculated point is I, which adds the K element in the sequence to V{ if(node[i].l==k&&node[i].r==k) {//the left and right endpoints are equal to K because of the changed single pointnode[i].sum+=v; Node[i].maxx+=v; return; } intMid= (NODE[I].L+NODE[I].R)/2; if(k<=mid) Add (i<<1, k,v);//if K is less than Mid, K is record in tree node I ElseAdd (i<<1)|1, k,v);//converselyUpdate (i);//Update}
Finally put down all the code basically can do template.
#include <iostream>#include<cstdio>using namespacestd;structtree{intL,r,sum,maxx;}; Tree node[ -];intn,m,a[ -];inlinevoidUpdateinti) {Node[i].sum=node[i<<1].sum+node[(i<<1)|1].sum; Node[i].maxx=max (node[i<<1].maxx,node[(i<<1)|1].maxx);} InlinevoidBuildintIintLintR) {NODE[I].L=l;node[i].r=R; if(l==R) {Node[i].maxx=A[l]; Node[i].sum=A[l]; return; } intMid= (L+R)/2; Build (I<<1, L,mid); Build ((I<<1)|1, mid+1, R); Update (i);} InlinevoidAddintIintKintv) { if(node[i].l==k&&node[i].r==k) {Node[i].sum+=v; Node[i].maxx+=v; return; } intMid= (NODE[I].L+NODE[I].R)/2; if(k<=mid) Add (i<<1, k,v); ElseAdd (i<<1)|1, k,v); Update (i);} InlineintSumintIintLintR) { if(node[i].l==l&&node[i].r==R)returnnode[i].sum; intMid= (NODE[I].L+NODE[I].R)/2; if(R<=mid)returnSUM (i<<1, L,r); Else if(L>mid)returnSum ((i<<1)|1, L,r); Else returnSUM (i<<1, L,mid) +sum ((i<<1)|1, mid+1, R);} InlineintMax (intIintLintR) { if(node[i].l==l&&node[i].r==R)returnNode[i].maxx; intMid= (NODE[I].L+NODE[I].R)/2; if(R<=mid)returnMax (i<<1, L,r); Else if(L>mid)returnMax ((i<<1)|1, L,r); Else returnMax (Max (i<<1, L,mid), Max ((i<<1)|1, mid+1, R));}intMain () {scanf ("%d%d",&n,&m); for(intI=1; i<=n;i++) scanf ("%d",&A[i]); Build (1,1, N); for(intI=1; i<=m;i++){ intc,a,b; scanf ("%d%d%d",&c,&a,&b); if(c==1) printf ("%d\n", SUM (1, A, b)); Else if(c==2) Add (1, A, b); Else if(c==3) printf ("%d\n", Max (1, A, b)); } }
Segment Tree tutorial (data structure, C + +)