线段树
在一类问题中,我们需要经常处理可以映射在一个坐标轴上的一些固定线段,例如说映射在OX轴上的线段。由于线段是可以互相覆盖的,有时需要动态地取线段的并,例如取得并区间的总长度,或者并区间的个数等等。一个线段是对应于一个区间的,因此线段树也可以叫做区间树。
线段树的构造思想
线段树是一棵二叉树,树中的每一个结点表示了一个区间[a,b]。每一个叶子节点表示了一个单位区间。对于每一个非叶结点所表示的结点[a,b],其左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b]。
线段树的运用
线段树的每个节点上往往都增加了一些其他的域。在这些域中保存了某种动态维护的信息,视不同情况而定。这些域使得线段树具有极大的灵活性,可以适应不同的需求。
线段树的实现(完全二叉树)
数据结构
type
TreeNode = record
b, e: Integer;
cover: Integer;
end;
插入算法
procedure Insert(p, a, b: Integer);
var
m: Integer;
begin
if Tree[p].cover = 0 then
begin
m := (Tree[p].b + Tree[p].e) div 2;
if (a = Tree[p].b) and (b = Tree[p].e) then
Tree[p].cover := 1
else if b <= m then Insert(p * 2, a, b)
else if a >= m then Insert(p * 2 + 1, a, b)
else begin
Insert(p * 2, a, m);
Insert(p * 2 + 1, m, b);
end;
end;
end;
统计算法
function Count(p: Integer): Integer;
begin
if Tree[p].cover = 1 then
Count := Tree[p].e – Tree[p].b
else if Tree[p].e – Tree[p].b = 1 then Count := 0
else Count := Count(p * 2) + Count(p * 2 + 1);
end;