C++ 线段树

线段树是一种高效的数据结构,用于处理区间查询和修改问题。本文详细介绍了线段树的存储方式、基本操作(建树、查询、修改)、以及区间修改的懒惰标记优化。提供了线段树的代码实现,并给出了两个例题,展示了如何应用线段树解决实际问题。

目录:

线段树基本常识

线段树的的存储

线段树的基本操作

1. 建树

2. 单点查询

3. 单点修改

4. 区间查询

5. 区间修改

例题推荐:

线段树 1

线段树 2


线段树基本常识

        线段树是一种二叉搜索树(即每个节点最多有两颗子树),与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

        如下图,就是一颗 [1,10] 的线段树的分解过程:

        由图可得出一个结论,线段树的最大深度不超过 log_{2} n ,且每一颗线段树需要 4*n 的辅助空间,如果没有开到 4*n ,那就完美 RE 了!!!

线段树的的存储

        线段树采用的是堆式储存法,即编号为 k 的节点的做儿子为 k*2、右儿子为 k*2+1、父亲节点为k/2;二进制运算优化就是 k<<1,k<<1|1,k>>1。

        通常来说,每个节点会存储:区间左边界、区间右边界、答案及其有关信息。

线段树的基本操作

1. 建树

        采用递归遍历整棵树,每次将区间分为左右两个区间,对与叶子接点直接赋值,非叶子节点由左右子树合并。

inline  void build(int k,int l,int r)//k为当前节点,[l,r]为当前区间
{ 
	if(l==r)//到达叶子节点,记录节点信息
    {
        sum[k]=a[l];
        return;//记得返回
    }
	int mid=(l+r)>>1;
	build(k*2,l,mid);//左右分别建树
	build(k*2+1,mid+1,r);
	sum[k]=sum[k*2]+sum[k*2+1];//合并区间信息
	return;
}

2. 单点查询

        采用类似二分的思想,将现区间 [ l,r ] 分为左右两个区间 [ l,mid ]、[ mid+1,r ] ,判断查找的位置 x 是在左区间还是在右区间,继续递归,如到达叶子节点,则直接返回节点信息。 

inline int find(int k,int l,int r,int x)//k为当前节点位置,[l,r]为当前区间,x为目标节点
{
	if(l==r) return sum[k];//找到目标节点,返回节点信息
	int mid=(l+r)>>1;
	if(x<=mid) return find(k*2,l,mid,x);//查询位置在左子树
	else  return find(k*2+1,mid+1,r,x);//查询位置在右子树
} 

3. 单点修改

        类似于单点查询,找到目标位置,直接进行修改,最后合并区间信息

inline void change(int k,int l,int r,int x)//k为当前节点位置,[l,r]为当前区间,x为目标节点
{
	if(l==r)//找到目标节点,进行修改
	{
		sum[k]+=x;//这里是区间累加
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) change(k*2,l,mid,x);//所查询位置在左子树
	else change(k*2+1,mid+1,r,x);//所查询位置在右子树
	sum[k]=sum[k*2]+sum[k*2+1];//合并区间信息
	return;
}

4. 区间查询

        目标区间 [ x,y ] ,当前区间 [ l ,r ] ,如果当前区间被目标区间包含,则直接返回区间信息,否则按照将当前区间分为左右两个区间进行查找的思想继续递归查询,最后所有返回区间的并集就是目标区间的答案。

inline int find(int k,int l,int r,int x,i
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值