线段树是一棵二叉树,他的每个节点包含了两个额外的属性start和end用于表示该节点所代表的区间。start和end都是整数,并按照如下的方式赋值:
- 根节点的 start 和 end 由 build 方法所给出。
- 对于节点 A 的左儿子,有 start=A.left, end=(A.left + A.right) / 2。
- 对于节点 A 的右儿子,有 start=(A.left + A.right) / 2 + 1, end=A.right。
- 如果 start 等于 end, 那么该节点是叶子节点,不再有左右儿子。
对于给定数组设计一个build方法,构造出线段树
样例:
给出[3,2,1,4],线段树将被这样构造
[0, 3] (max = 4)
/ \
[0, 1] (max = 3) [2, 3] (max = 4)
/ \ / \
[0, 0](max = 3) [1, 1](max = 2)[2, 2](max = 1) [3, 3] (max = 4)
思路:
对于线段树root,给定查询范围[start,end],若[start,end]超出root所表示的范围,则规范start或end的值。
若[start,end]位于当前节点node的区间内,且节点node的count值为0,则[start,end]中也不可能存在元素,返回0。
若[start,end]就是当前节点node的区间,返回node的count值。
若start大于node右子树的start值,则在node的右子树中进行查询;若end小于node的左子树的end值,则在node的左子树中进行查询;否则,在左子树中查询[start,node->left->end],右子树中查询[node->right->start,end],并取二者之和。
#ifndef C247_H
#define C247_H
#include<iostream>
using namespace std;
class SegmentTreeNode{
public:
int start, end, count;
SegmentTreeNode *left, *right;
SegmentTreeNode(int start, int end, int count){
this->start = start;
this->end = end;
this->count = count;
this->left = this->right = NULL;
}
};
class Solution {
public:
/*
* @param root: The root of segment tree.
* @param start: start value.
* @param end: end value.
* @return: The count number in the interval [start, end]
*/
int query(SegmentTreeNode *root, int start, int end) {
// write your code here
if (start > end || !root)
return 0;
//当查询范围超出当前节点范围时,规范其范围
if (start < root->start)
return query(root, root->start, end);
if (end>root->end)
return query(root, start, root->end);
SegmentTreeNode *node = root;
//若查询范围小于当前节点范围,且当前节点count为0,直接返回0
if (start >= node->start&&end <= node->end&&node->count == 0)
return 0;
//若查询范围等于当前节点范围,返回当前节点的count值
if (start == node->start&&end == node->end)
return node->count;
//根据查询范围改变搜索节点
if (start >= node->right->start)
return query(node->right, start, end);
else if (end <= node->left->end)
return query(node->left, start, end);
else
{
int l = query(node->left, start, node->left->end);
int r = query(node->right, node->right->start, end);
return l + r;
}
}
};
#endif