线段树:线段树是一种平衡二叉查找树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。主要的处理思想是基于分治的思想。它的逻辑结构如下:
设根节点的区间为[a,b),区间长度为L = b - a,线段树的性质:
(1)线段树是一个平衡树,树的高度为log(L)
(2)线段树把区间上的任意长度为L的线段都分成不超过2log(L)线段的并
线段树基础存储结构如下:(这里使用数组模拟指针,类似堆的存储结构)
typedef struct{<pre name="code" class="cpp"> int left,right;
int cover, mid;
}TreeNode;创建线段树
void BuildLineSegTree(int left,int right,int nodeNum) { node[nodeNum].left = left; node[nodeNum].right = right; node[nodeNum].mid = left + (right - left) / 2; node[nodeNum].cover = 0; //判断是否是叶子节点 if(left != right-1) { BuildLineSegTree(left,node[nodeNum].mid,2 * nodeNum); BuildLineSegTree(node[nodeNum].mid,right,2 * nodeNum + 1); } }插入线段树
void InsertLineSegTree(int left,int right,int nodeNum) { //判断区间是否完全覆盖 if(node[nodeNum].left == left && node[nodeNum].right == right) { node[nodeNum].cover += 1; return ; } if(right <= node[nodeNum].mid) { //线段在左子树上 return InsertLineSegTree(left,right,2*nodeNum); } else if(left >= node[nodeNum].mid) { //线段在右子树上 return InsertLineSegTree(left,right,2 * nodeNum + 1); } else { //线段一部分在左子树上,一部分在右子树上 return InsertLineSegTree(left,node[nodeNum].mid,2*nodeNum)||InsertLineSegTree(node[nodeNum].mid,right,2*nodeNum + 1); } }
int SearchLineSegTree(int left,int right,int nodeNum) { if(node[nodeNum].left == left && node[nodeNum].right == right) { //线段完全覆盖,若该线段存在则返回1,否则返回0 return node[nodeNum].cover; } if(right <= node[nodeNum].mid) { //线段在左子树 return SearchLineSegTree(left,right,2 * nodeNum); } else if(left >= node[nodeNum].mid) { //线段在右子树 return SearchLineSegTree(left,right,2 * nodeNum + 1); } else { //线段一部分在左子树,一部分在右子树 return SearchLineSegTree(left,node[nodeNum].mid,2*nodeNum)&&SearchLineSegTree(node[nodeNum].mid,right,2*nodeNum + 1); } }
int DeleteLineSegTree(int left,int right,int nodeNum) { if(node[nodeNum].left == left && node[nodeNum].right == right) { //线段完全覆盖,若该线段存在则返回1,否则返回0 int ret = node[nodeNum].cover; node[nodeNum].cover = node[nodeNum].cover > 0 ? node[nodeNum].cover - 1 : 0; return ret; } if(right <= node[nodeNum].mid) { //线段在左子树 return DeleteLineSegTree(left,right,2 * nodeNum); } else if(left >= node[nodeNum].mid) { //线段在右子树 return DeleteLineSegTree(left,right,2 * nodeNum + 1); } else { //线段一部分在左子树,一部分在右子树 return DeleteLineSegTree(left,node[nodeNum].mid,2*nodeNum)&&DeleteLineSegTree(node[nodeNum].mid,right,2*nodeNum + 1); } }