线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元子表示的区间为[a,(a+b)/2],右儿子表示
本的线段树结构,但只有这些并不能做什么,就好比一个程序有输入没输出,根本没有任何用处。 录线段有否被覆盖,并随时查询当前被覆盖线段的总长度。
那么此时可以在结点结构中加入一个变量 int count;代表当前结点代表的子树中被覆盖的线段长度和。
这样就要在插入(删除)当中维护这个 count 值,于是当前的覆盖总值就是根节点的于查找一个有序数组给定区间里的最大值或者对该区间求和。
属于初级的线段树应用,多数是较难的应用,例如对有序数组进行区间成段更新、区间成段加减等等的操作。这些较难应用一般需要利用到“延迟标记” 。
迟标记的作用是延迟对子区间的更新,优点是更新操作不必“进行到底” 。
例如将上图中的有序数组的下标在区间[1,3]上的数全部加 1,再全部减 7。
利用延时标记思想则两次更新均只需更新到第二层,延迟标记将记录操作“减 6” ,当查询操作涉及的区间在[1,3]内时区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶子节点[a,b],它的左儿的区间为[(a+b)/2+1,b]。
因此线段树是平衡二叉树,最后的子节点数目为 N,即整个线段区间的长度。
上面介绍的是基最简单的应用就是记count值了。
另外也可以用上面两种应用延再执行更新操作。
以下为模板代码
1 #define MAXSIZE 200000 2 int val[MAXSIZE+1]; 3 struct node 4 { 5 int max; 6 int left; 7 int right; 8 }tree[MAXSIZE<<3]; 9 int max(int c,int y) 10 { 11 return x>y?x:y; 12 } 13 int creat(int root,int left,int right) 14 {//the tree bais by root 15 tree[root].left=left; 16 tree[root].right=right; 17 if(left==right) 18 return tree[root].max=val[left]; 19 int a,b,middle=(left+right)/2; 20 a=creat(root<<2,left,middle); 21 b=creat(root<<2|1,left|1,middle); 22 return tree[root].max=max(a,b); 23 } 24 int calculate(int root,int left,int right) 25 {//in the tree on the root,get max during[left,right] 26 if(tree[root].left>right||tree[root].right<=right) 27 return 0; 28 if(left<=tree[root].left&&tree[root].right<=right) 29 return tree[root].max; 30 int a,b; 31 a=creat(root<<2,left,middle); 32 b=creat(root<<2|1,left,middle); 33 return tree[root].max=max(a,b); 34 } 35 int updata(int root,int pos,int val) 36 {//in the tree on root,make'pos'exchange'val' 37 if(pos<tree[root].left||tree[root].right<pos) 38 return 0; 39 if(tree[root].left==pos&&tree[root].right==pos) 40 return tree[root].max=val; 41 int a,b; 42 a=updata(root<<2,left,middle); 43 b=updata(root<<2|1,left,middle); 44 return tree[root].max=max(a,b); 45 }