区间信息维护与查询【线段树 】 - 原理1 线段树的基本操作
创始人
2024-02-27 06:31:38

区间信息维护与查询【线段树 】 - 原理1 线段树的基本操作

线段树(segment tree)是一种基于分治思想的二叉树,它的每个节点都对应一个[L , R ]区间,叶子节点对应的区间L =R 。每一个非叶子节点[L , R ]其左子节点的区间都为[L , (L +R )/2],右子节点的区间都为[(L +R )/2+1, R ]。

[1, 10]区间的线段树如下图所示:

在这里插入图片描述

因为线段树对区间进行二分,是一棵平衡二叉树,所以树高为O(logn ),树上的操作大多与树高相关。

线段树主要用于更新和查询,一般至少有一个是区间更新或查询。更新和查询的种类变化多样,灵活运用线段树可以解决多种问题。

【1】 线段树的存储方式

对于区间最值(最大值或最小值)查询问题,线段树的每个节点都包含三个域:l、r、 mx,其中l 和r 分别表示区间的左右端点,mx表示[l , r ]区间的最值。

本题以最大值为例,若有10个元素a [1…10]={5, 3, 7, 2, 12, 1, 6, 4, 8, 15},则构建的线段树如下图所示。

在这里插入图片描述

线段树除了最后一层,其他层构成一颗满二叉树,因此采用顺序存储方式,用一个数组tree[]存储节点。

若一个节点的存储下标为k ,则其左子节点的下标为2k ,其右子节点的下标为2k +1。

在这里插入图片描述

线段树根节点的存储下标为1,其左右子节点的存储下标分别为2、3,有10个元素的线段树,其存储下标如下图所示:

在这里插入图片描述

【2】创建线段树

可以采用递归的方法创建线段树,算法步骤如下:

① 若是叶子节点(l =r ),则节点的最值就是对应位置的元素值。

② 若是非叶子节点,则递归创建左子树和右子树。

③ 节点的区间最值等于该节点左右子树最值的最大值。

[ 算法代码]

void build(int k , int l , int r){ //创建线段树,节点的存储下标为k,节点的区间为 [l , r]tree[k].l = l;tree[k].r = r;if(l == r){tree[k].mx = a[l];return;}int mid , lc , rc;mid = (l + r) / 2; //划分点lc = k * 2; // 左子节点的存储下标rc = k * 2 + 1; //右子节点的 存储下标build(lc , l , mid);build(rc , mid + 1, r);tree[k].mx = max(tree[lc].mx , tree[rc].mx); //节点的最大值等于左右子节点 最值的最大值
}
【3】点更新

点更新指修改一个元素的值,例如将a [i ]修改为v 。采用递归进行点更新,算法步骤如下。

① 若是叶子节点,满足l =r 且l =i ,则修改该节点的最值为v。

② 若是非叶子节点,则判断是在左子树中更新还是在右子树中更新。

③ 返回时更新节点的最值。

例如,修改第5个节点的值为14时,先从树根向下找第5个元素所在的叶子节点,将其最值修改为14,返回时更新路径上所有节点的最值(左右子节点最值的最大值)。

在这里插入图片描述

[ 算法代码]

void update(int k , int i , int v){ // 将a[i] 更新为 vif(tree[k].l == tree[k].r && tree[k].l == i){ //找到a[i]tree[k].mx = v;return ;}int mid , lc, rc;mid = (tree[k].l + tree[k].r) / 2; //划分点lc = k * 2; // 左子节点的存储下标rc = k * 2 + 1; // 右子节点的 存储下标if(i <= mid){update(lc , i ,v); // 到左子树中 更新}else{update(rc , i , v); //到 右子树中更新}tree[k].mx = max(tree[lc].mx , tree[rc].mx); // 返回时更新最值
}
【4】区间查询

区间查询指查询一个[l , r ]区间的最值。采用递归的方法进行区间查询的算法步骤如下:

① 若节点所在的区间被查询区间[l , r ]覆盖,则返回该节点的最值。

② 判断是在左子树中查询,还是在右子树中查询。

③ 返回最值。

例如,在[1, 10]的线段树中查询[3, 5]区间的最值,过程如下。

① 计算树根[1, 10]的划分点,mid=(1+10)/2=5,待查询区间l=3、r =5、r ≤mid,说明查询区间在左子树中,到左子树中查询

在这里插入图片描述

② 计算左子树树根[1, 5]的划分点,mid=(1+5)/2=3,待查询区间l =3、r =5、r >mid、l ≤mid,说明查询区间横跨左右子树两个区间,需要到左、右子树中查询[3, 5],然后求最大值。

在这里插入图片描述

③ 计算左子树树根[1, 3]的划分点,mid=(1+3)/2=2,待查询区间l =3、r =5、l >mid,说明查询区间在右子树中,到右子树中查询,该右子树[3, 3]被查询区间覆盖,返回最值7。

在这里插入图片描述

④ 右子树为[4, 5],待查询区间为[3, 5],被查询区间覆盖,返回区间最值12。

在这里插入图片描述

⑤ 左右子树分别返回最值7、12,然后求最大值,即可得到查询区间[3, 5]的最值为12。

在这里插入图片描述

[ 算法代码]

int query(int k , int l,  int r){ // 求[l ,r] 区间的最值if(tree[k].l >= l && tree[k].r <= r){ // 查询区间覆盖该节点区间return tree[k].mx;	}int mid , lc , rc;mid = (tree[k].l + tree[k].r ) / 2; //划分点lc = k * 2; //左子节点的存储下标rc = k * 2 + 1; //右子节点的 存储下标int Max = -inf; //注意: 局部变量可以,全局变量不可以if(l <= mid){Max = max(Max , query(lc , l , r)); // 到左子树中查询}if(r > mid){Max = max(Max , query(rc , l , r)); //到右子树中查询}return Max;
}

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...