本文共 1083 字,大约阅读时间需要 3 分钟。
近几天有些自闭,我觉得自己身上有太多的东西没有学会,我决定一点点来,每天争取学一个知识点,今天份记录,线段树。
线段树是一种以二叉树为原型,将树形结构各个节点划分为区间的一种结构,其中全部的区间就是根节点,如一个节点【l,r】,其子节点就是【l,l+r/2】与【(l+r)/2+1,r】,也就是把区间二等分,直到最后的叶子节点全部都是一个单一数据。
如果区间长度为n,那么树的高度最大为log2(n-1)+2.,所以如果要修改某个值,包括这个值的点在每一层区间当中只有一个,所以更改的次数最大值即为log2(n-1)+2次,既整颗树的高度,容易看出时间复杂度仅仅只有log2n。
如果要进行区间查询,一般要从树的叶子节点出发,查询其包含的内容所构成的子区间时,只需要一层层往上找,最终找到所有包含内容的子区间,当然也可以取一些别的零碎的区间,可以用来解决一些查找的区间问题。
建树函数:
void dataup(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];} //用于更新每个父节点的数据
void build(int l,int r,int jd){
//l表示左区间,r表示有区间端点,jd表示节点
if(l==r) {
//抵达叶节点回溯,此处用了递归的思想
sum[jd]=p[l]; //p是存储的数据元素,sum表示的是线段树存储数组值,当前sum是求整个区间的和,当为不同区间是sum不同
return;
}
int m=(l+r)>>1;
build(l,m,jd<<1);
build(m+1,r,jd<<1|1);
dataup(jd);
}
而修改一个数据的值相对于简单一点,就是一直遍历到叶子节点,把那个改变的值在本点加上,然后回溯更新父节点的值,利用上面的dataup函数即可,不多做赘述。
而相对于修改一点的值,修改整个区间则要更麻烦一些,我们需要记一下需要修改的值的区间左右端点,然后构成函数,当前所操作的区间如果包含于修改的区间之内那么我们就把这个区间的数据改变,需要右区间端点减左区间端点加一乘要改变的数,如果不完全包含于修改区间也没关系,我们写个判断,看这个区间是否完全与需要操作的区间无交集,如果有那么向下递归,递归的作用就是更新一下前面的节点数据。这样就完成了整个树结构的区间操作的更新。
区间查询也不麻烦,从开始往下找,当找到完全包含于查询区间的数值上,加在答案上就可以了。
这就是线段树基本实现方式,过两天更新两道题,我要找找当初网络赛干掉我的题的题解,争取早日更新。
加油,臭咸鱼!!
转载地址:http://pomwi.baihongyu.com/