线段树是描述单个或若干区间并的树形结构,属于平衡树的一种(平衡树是指左右子树的层数之差不超过1)。使用线段树要求知道所描述的区间端点可能取到的值。
线段树在一些acm题目中经常见到,这种数据结构主要应用在计算几何和地理信息系统中。下图就为一个线段树:
(注:可能你见过线段树的不同表示方式,但是都大同小异,根据自己的需要来建就行。)
对于线段树中的每一个非叶子节点[a,b],它的左孩子表示的区间为[a,(a+b)/2],右孩子表示的区间为[(a+b)/2,b]。因此线段树是平衡二叉树,最后的叶子节点数目为N,即整个线段区间的长度。
线段树是一棵二叉树,记为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为叶子节点。
线段树中的结点一般采取如下数据结构:
//定义线段树的结点
struct Node{
int left,right; //区间的左右值
int count; //count=1表示结点所表示的区间被完全覆盖,count=0表示结点所表示的区间未被完全覆盖
Node *leftchild;
Node *rightchild;
};
线段树的建立:
//建立线段树
Node *build(int k,int r) //k表示区间左值,r表示区间右值
{
Node *root=new Node;
root->left=k;
root->right=r;
root->count=0;
root->leftchild=NULL;
root->rightchild=NULL;
if((k+1)<r)
{
int mid=(k+r)/2;
root->leftchild=build(k,mid);
root->rightchild=build(mid,r);
}
return root;
}
插入线段:
//插入算法
void Insert(Node *root,int a,int b)
{
int m;
if(root->count==0)
{
m=(root->right+root->left)/2;
if(a==root->left&&b==root->right)
root->count=1;
else if(b<=m)
Insert(root->leftchild,a,b);
else if(a>=m)
Insert(root->rightchild,a,b);
else if(a<m&&b>m)
{
Insert(root->leftchild,a,m);
Insert(root->rightchild,m,b);
}
}
}
统计被覆盖的线段段数:
//统计算法
int Count(Node *root)
{
int m,n;
if(root->count==1)
return (root->right-root->left);
else if((root->right-root->left)==1)
return 0;
m=Count(root->leftchild);
n=Count(root->rightchild);
return m+n;
}
线段树的应用:
引例:总线段从10000到60000,给出四个子线段:[10000,22000],[30300,55000],[44000,60000],[55000,60000],求解出这
个子线段的总长度,值得考虑的问题是这四个子线段有重叠的部分,也有断开的本分,而我们要求的是去除断开部分和去除重
叠部分的总长度。
完整代码如下: #include<stdio.h>
//定义线段树的结点
struct Node{
int left,right; //区间的左右值
int count; //count=1表示结点所表示的区间被完全覆盖,count=0表示结点所表示的区间未被完全覆盖
Node *leftchild;
Node *rightchild;
};
//建立线段树
Node *build(int k,int r) //k表示区间左值,r表示区间右值
{
Node *root=new Node;
root->left=k;
root->right=r;
root->count=0;
root->leftchild=NULL;
root->rightchild=NULL;
if((k+1)<r)
{
int mid=(k+r)/2;
root->leftchild=build(k,mid);
root->rightchild=build(mid,r);
}
return root;
}
//插入算法
void Insert(Node *root,int a,int b)
{
int m;
if(root->count==0)
{
m=(root->right+root->left)/2;
if(a==root->left&&b==root->right)
root->count=1;
else if(b<=m)
Insert(root->leftchild,a,b);
else if(a>=m)
Insert(root->rightchild,a,b);
else if(a<m&&b>m)
{
Insert(root->leftchild,a,m);
Insert(root->rightchild,m,b);
}
}
}
//统计算法
int Count(Node *root)
{
int m,n;
if(root->count==1)
return (root->right-root->left);
else if((root->right-root->left)==1)
return 0;
m=Count(root->leftchild);
n=Count(root->rightchild);
return m+n;
}
int main()
{
int qz,qy,n,i,j,x,y;
Node *p;
scanf("%d%d",&qz,&qy);
p=build(qz,qy);
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d%d",&x,&y);
Insert(p,x,y);
}
printf("%d\n",Count(p));
return 0;
}
运行结果截图: