线段树的基本概念
1.线段树是一种特殊的平衡二叉查找树,使用线段树,可以实现数据的添加,查找和删除等操作. 相比二叉搜索树,线段树不同的地方在于,线段树的根节点表示了一个完整的单元区间,线段树中的内部节点,将整个区间划分成了更小的子区间,而叶节点表示了区间间隔为1的单位区间
2.对于线段树中的任意一个节点P,如果它表示区间[a,b]
它的左孩子是区间[a,(a+b)/2];
它的右孩子是区间[(a+b)/2+1,b];
它们也是一颗以对应区间为根的线段树
当区间左右端点相等,即a等于b时,该节点是叶子节点
3.如果一个线段树代表区间[a,b],那么该线段树一共有b-a+1个叶节点,它可以存储a到b之间的所有整数。 例如,根节点代表的区间是[0,5],那么它会被拆分为[0,0],[1,1],[2,2]...[5,5],6条单位线段,可以保存0到5这6个整数
开辟的数组存储的是二叉树从根节点按层序遍历(不同区间内数字的个数)
操作:
1.线段树的数据插入,使用a来存储线段树中的数据,变量pos对应正在访问的数组下标,left和right表示当前正在处理的区间的左右端点,数字num是待插入的数字
void tree_insert(vector<int>&a,int pos,int left,int right,int num){
//区间left到right中保存的数字增加了1个
a[pos]++; //数组的第一个节点(根节点a[0])
//如果此时待添加的数字num和左右端点相同
if(num==right&&num==left){
//当前的区间是单位区间,并且这个单位区间就对应了数字num
return;
}
//计算区间的中点
int mid=(left+right)/2;
//计算该区间的左孩子区间对应的数组下标
int left_child=pos*2+1;
int right_child=pos*2+2;
if(num<=mid){
//插入到左孩子区间中
tree_insert(a,left_child,left,mid,num);
}else{
//插入到右孩子区间中
tree_insert(a,right_child,mid+1,right,num);
}
}
线段树的数据查找
int tree_search(vector<int>&a,int pos,int left,int right,int num){
if(num==right&&num==left){
return a[pos];
}
int mid=(left+right)/2;
int left_child=pos*2+1;
int right_child=pos*2+2;
if(num<=mid){
//左区间查找
return tree_search(a,left_child,left,mid,num);
}else{
//右区间查找
return tree_search(a,right_child,mid+1,right,num);
}
}