开启掘金成长之旅!这是我参与「掘金日新计划 · 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);
}