线段树作为一种二叉搜索树,在处理区间问题上大大提高了效率。
首先我们以一个数组为例构建线段二叉树的示意图:
数组为 a[1...5] = {5, 4, 2, 3, 1}
[1, 5]
/ \
[1, 3] [4, 5]
/ \ / \
[1, 2] [3, 3] [4, 4] [5, 5]
/ \
[1, 1] [2, 2]
如上示意图所示, 每个结点内的主要信息就是数组a的下标范围,如此, 在求区间最值与区间和就十分方便了。
在线段树的操作中,最基本就是构造线段树,以及更新线段树。
下面以求区间和与求区间最小值为例。
首先确定线段树的数据结构:
struct SegTree //使用静态树的方法来保存信息
{
int left, right; // 结点所示区间[l, r]
int minv;//最小值
int sum;//区间和
};
SegTree stree[maxn];//自行定义maxn
然后是建立区间树的函数:
void build(int v, int l, int r) // v为所用的stree节点, l,r表示范围
{
stree[v].left = l;
stree[v].right = r;
if(l == r)
{//区间内只有一个值时,最小值和区间和便确定了
stree[v].sum = A[l];
stree[v].minv = A[l];
}
else
{//递归构造,并更新sum与minv
int mid = (l + r) / 2;
build(2 * v, l, mid);
build(2 * v + 1, mid + 1, r);
stree[v].sum = stree[v*2].sum + stree[v*2+1].sum;
stree[v].minv = min(stree[v*2].minv, stree[v*2+1].minv);
}
}
build(1, 1, n);
线段树更新:
void update(int id, int pos, int x) //id为其实stree的下标,pos为要更新a[i]的下标, x为要更新的值
{
if(stree[id].left == stree[id].right)//区间只有一个数时,直接完成更新
{
A[stree[id].left] = x;
stree[id].minv = x;
stree[id].sum = x;
}
else
{ //根据 l, r分别向左右进行搜索
int mid = (stree[id].left + stree[id].right) / 2;
if(pos <= mid) update(id * 2, pos, x);
else update(id * 2 + 1, pos, x);
stree[id].sum = stree[id*2].sum + stree[id*2+1].sum;
stree[id].minv = min(stree[id*2].minv, stree[id*2+1].minv);
}
}
update(1, pos, v);
求区间和:
int findSum(int root, int l, int r)
{
if(stree[root].left >= l && stree[root].right <= r) // 当节点区间包含在[l, r] 中时,直接返回区间和
{
return stree[root].sum;
}
else
{//分别计算左右子树的区间和
int sumL = 0, sumR = 0;
int mid = (stree[root].left + stree[root].right) / 2;
if(l <= mid)
sumL = findSum(root * 2, l, r);
if(r > mid)
sumR = findSum(root * 2 + 1, l, r);
return sumL + sumR;
}
}
求区间最小值:
int findmin(int root, int l, int r) // root为树根, l, r为指定区间
{
if(stree[root].left >= l && stree[root].right <= r) //区间中只有一个数时,直接返回
{
return stree[root].minv;
}
else
{//分别查找左右子树
int minL = INF, minR = INF;
int mid = (stree[root].left + stree[root].right) / 2;
if(l <= mid)
minL = findmin(root * 2, l, r);
if(r > mid)
minR = findmin(root * 2 + 1, l, r);
return min(minL, minR);//返回最小值
}
}
运用以上代码,就基本能在O(log2n)时间内完成相应的操作,提高查找效率。根据要求不同,也可修改对应的数据结构来满足需求。