线段树之——查询答案(持续更新✨)

92 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」第13天,点击查看活动详情 上篇文章我们讲解了线段树的建立过程,

我们建立结点时不停往下二分线段,最后到了叶子节点,我们就给它设置原始数据。

PS:绿色数字为步骤数

我们发现叶子节点的,所以不能再建立左右子树了,叶子的pushup也就没用

在结束最后叶子节点的建立后,我们的建树函数就会调用函数,将底层的数据合并到上一层

void pushup(ll root){//例子中的数据为sum(和) 即父节点的sum为子节点的sum合并而来
    tree[root].sum=tree[LL(root)].sum+tree[RR(root)].sum;
}

然后该层结点又会把自己数据合并给更上一层

如此这番,我们从最底层叶子结点结束建立后,到根节点结束建立,我们就将每个结点都创建完毕啦。

接着我们来讲下线段树查询答案的步骤

我们可以发现,在建立方面,我们比正常的创建线性数组的效率要低,且空间花费也更多

但是我们正是在查询答案方面效率要比线性查询更优,

查询的思想跟我们建树的思想很像:

倘若当前区间恰好是要查询的区间,那么就返回结果。

如果当前区间包含目标区间:

1.目标区间在中点左侧,就递归查询左区间

2.目标区间在中点右侧,就递归查询右区间

最后返回的总区间答案是由两个子区间答案合并而来

int query(int root,int l,int r)
//当前到了编号为root的节点,查询[l..r]的和{
	if(a[root].l==l&&a[root].r==r) return a[root].sum;
	//如果当前区间就是询问区间,完全重合,那么显然可以直接返回
	int mid=(a[root].l+a[root].r)/2;
	if(r<=mid) return query(k*2,l,r);
	//如果询问区间包含在左子区间中
	if(l>mid) return query(k*2+1,l,r);
	//如果询问区间包含在右子区间中
	return query(root*2,l,mid)+query(root*2+1,mid+1,r);
	//如果询问区间跨越两个子区间
}