n由于两个子线段是尽量平均的,因此长度为N的线段树的深度为O(logN)。
n给定一个叶子p, 从根到p路径上所有结点(即p的所有直系祖先)代表的线段都包含点p, 且其他结点代表的线段都不包含点p。
n对于每个线段,都可以看作O(logN)条线段的并,且每两条线段间不存在公共部分。(分治思想)
线段树的写法:
/*线段树的基本结点结构,[l,r]表示这个结点所代表的线段,left和right分别指向左右儿子。*/
struct node {
int l, r;
node *left, *right;
// something else
};
线段树建立 :
node* build(int l,int r) {
node *p = new node;
p->l = l;
p->r = r;
if (l==r) //叶子结点
p->left = p->right=NULL;
else { //非叶子结点
int center = (l+r)/2; //平均分成两半递归建立
p->left = build(l,center);
p->right = build(center+1,r);
}
// do something
return p;
}
区间分解 :
void divide(node *p, int l, int r) {
int center = (p->l+p->r)/2;
if (l==p->l && r==p->r) { //找到一个分解区间
// do something
return;
}
if (r<=p->center) //区间完全在左子树上
divide(p->left,l,r);
else if (l>p->center) //区间完全在右子树上
divide(p->right,l,r);
else { //区间在两边子树上都有
divide(p->left,l,center);
divide(p->right,center+1,r);
}
// do something
}
n线段树主要集中于设计结点的附加信息和在计算过程中对附加信息进行维护,并且使每次计算的操作时间复杂度为O(logN)。这也是我们设计线段树的目标。