线段树(segment tree)
线段树是一棵二叉树,记为T(a, b),参数a,b表示区间[a,b],其中b-a称为区间的长度,记为L。
线段树T(a,b)递归定义类似为:
若L>1 : [a, (a+b) div 2]为 T的左儿子; [(a+b) div 2,b]为T 的右儿子。 若L=1 : T为叶子节点。
上面的线段树只是一种可能的形式,具体按自己的需求定义,只要保证父节点“覆盖”所有的子节点
例:
桌子上零散地放着若干个盒子,桌子的后方是一堵墙。如图所示。现在从桌子的前方射来一束平行光, 把盒子的影子投射到了墙上。问影子的总宽度是多少?
这道题目是一个经典的模型。在这里,我们略去某些处理的步骤,直接分析重点问题,可以把题目抽象地描述如下:x轴上有若干条线段,求线段覆盖的总长度,即S1+S2的长度。
code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node
{
int lvalue, rvalue;
int data;
struct Node *lchild;
struct Node *rchild;
} Node;
Node *Build(int l, int r)
{
Node *root;
if (l >= r)
return NULL;
root = (Node *)calloc(1, sizeof(Node));
root->lvalue = l;
root->rvalue = r;
root->data = 0;
root->lchild = NULL;
root->rchild = NULL;
if (l + 1 < r) {
int mid = (l + r) >> 1;
root->lchild = Build(l , mid) ;
root->rchild = Build(mid , r) ;
}
return root;
}
void Insert(Node *root, int c, int d)
{
if (!root)
return;
if(c <= root->lvalue && d >= root->rvalue)
root->data++;
else {
int mid = (root->lvalue + root->rvalue) >> 1;
if (d <= mid)
Insert(root->lchild, c, d);
else if(c >= mid)
Insert(root->rchild, c, d);
else {
Insert(root->lchild, c, mid);
Insert(root->rchild, mid, d);
}
}
}
void Delete(Node *root, int c, int d)
{
if (!root)
return;
if (c <= root->lvalue && d >= root->rvalue)
root->data--;
else
{
int mid = (root->lvalue + root->rvalue) >> 1;
if (d <= mid)
Delete(root->lchild, c, d);
else if(c >= mid)
Delete(root->rchild, c, d);
else {
Delete(root->lchild, c, mid);
Delete(root->rchild, mid, d);
}
}
}
void Find(Node *root,int a,int b, int *count)
{
int mid;
if (!root)
return;
if(root->data > 0) {
*count += (root->rvalue - root->lvalue);
return;
}
mid = (root->lvalue + root->rvalue) >> 1;
if(b <= mid)
Find(root->lchild, a, b, count);
else if(a >= mid)
Find(root->rchild,a, b, count);
else {
Find(root->lchild, a, mid, count);
Find(root->rchild, mid, b, count);
}
}
int value[][2] = {
{1, 7},
{8, 17},
{15, 23},
{34, 40},
{38, 42},
{36, 41}
};
int main()
{
int count = 0;
int i;
Node *root = Build(9, 101);
for (i = 0; i < sizeof(value) / sizeof(value[0]); i++)
Insert(root, value[i][0], value[i][1]);
Find(root, 4, 50, &count);
printf("count: %d\n", count);
Delete(root, 36, 41);
count = 0;
Find(root, 4, 50, &count);
printf("count: %d\n", count);
Delete(root, 38, 42);
count = 0;
Find(root, 4, 50, &count);
printf("count: %d\n", count);
return 0;
}