线段树
一颗线段树的构造就是根据区间的性质的来构造的, 如下是一棵区间[0, 3]
的线段树,每个[start, end]
都是一个二叉树中的节点。
[0, 3]的线段树
区间划分大概就是上述的区间划分。可以看出每次都将区间的长度一分为二,数列长度为n
,所以线段树的高度是log(n)
,这是很多高效操作的基础。
上述的区间存储的只是区间的左右边界。我们可以将区间的最大值加入进来,也就是树中的Node
需要存储left
,right
左右子节点外,还需要存储start
, end
, val
区间的范围和区间内表示的值。
可以储存不同的值,例如区间内的最大值,最小值,区间的求和等等。
将区间的最大值加入进来
数据结构:
segment tree的创建
class Solution {
public:
/*
* @param start: start value.
* @param end: end value.
* @return: The root of Segment Tree.
*/
SegmentTreeNode * build(int start, int end) {
// write your code here
SegmentTreeNode *root=new SegmentTreeNode(start,end);
if(start==end) return root;
else if(start>end) return nullptr;
else {
root->left=build(start,(start+end)/2);
root->right=build((start+end)/2+1,end);
return root;
}
}
};
segment tree的查询
class Solution {
public:
/**
* @param root: The root of segment tree.
* @param start: start value.
* @param end: end value.
* @return: The maximum number in the interval [start, end]
*/
int query(SegmentTreeNode * root, int start, int end) {
// write your code here
start=max(start,root->start);
end=min(end,root->end);
if(root->start==root->end) return root->max;
int mid=(root->start+root->end)/2;
int l=query(root->left,start,end);
int r=query(root->right,start,end);
if(end<=mid) return l;
else if(start>mid) return r;
else return max(l,r);
}
};
segment tree的更新:
class Solution {
public:
/**
* @param root: The root of segment tree.
* @param index: index.
* @param value: value
* @return: nothing
*/
void modify(SegmentTreeNode * root, int index, int value) {
// write your code here
if(root->start==root->end&&root->end==index){
root->max=value;
return;
}
int mid=(root->start+root->end)/2;
if(index<=mid) modify(root->left,index,value);
else modify(root->right,index,value);
root->max=max(root->left->max,root->right->max);
}
};