线段树讲解第二章之——基础实现(持续更新✨)

91 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」第11天,点击查看活动详情

线段树实现

在算法竞赛中,线段树的存储一般用的是堆式存储法


即id为k的节点,它的左孩子id为2*k ,右孩子id为2*k+1 .

创建孩子时,

我们不妨可以用位运算加速一下,左孩子id用 k<<1表示,左孩子id用 k<<1|1表示


解释一下这两个位运算的意思:

左孩子对应k<<1 ------> k二进制下向左移一位,即乘以2

右孩子对应k<<1|1------> k左移1位后,最后一位二进制位必然为0,异或1之后等于+1


一般情况下我们的一个节点里会存储:左孩子,右孩子,以及问题相关的属性值,比如sum,max

struct Tree{
    int Left,Right,val;
}Tree[(N<<2)+10];//这里开了4*N+5的容量  

大多数情况下,假设题目所给数据量为n,那么用堆式存储法需要开辟的空间范围是 *~ *


本段证明修改自大佬:千叶繁华

不妨设数据量,目前线段树是一棵叶子结点数为的满二叉树。

倘若更大一些,但尚未超过时,想必线段树要开到2k+1。

因此,当,即时,

我们线段树所开大小与叶子结点数为的满二叉树大小相同,

而该满二叉树的节点数

可得 ceil----向上取整

由上述证明可知,为了保险起见,对于线段树类型的问题,我们最好将数组空间开到

线段树建立

void build(ll root, ll l, ll r) {
	tree[root] = { l,r };
	if (l == r) { cin >> x; tree[root] = { l,l,x,0 }; return; }//这里的第四个属性是sum
	int mid = (l + r) >> 1;
	build(root<<1, l, mid), build(root<<1|1, mid + 1, r) ;
	pushup(root);
}