线段树的构建和查询

(本系列函数参数表示为\(k\)节点存储区间\([l,r]\)的和,查询/修改的点为\(x\),查询/修改的区间为\([x,y]\)

上一篇简单介绍了以下线段树,本文就说一下线段树的构建与查询。(本系列均以区间和为例)

 

1.构建

我们从线段树的定义可以知道,\(k\)节点储存\(ls(k)\)\(rs(k)\)两节点的和。所以,我们采用递归构建线段树。当区间的左端点与右端点重合时,即为叶子结点。非叶子结点在回溯中计算出。

void build(int k, int l, int r)
{
	if(l == r)
	{
		tree[k] = val[k];
		return;
	}
	int mid = (l + r) >> 1;
	build(ls(k), l, mid);
	build(rs(k), mid + 1, r);
	tree[k] = tree[ls(k)] + tree[rs(k)];
}

 

2.查询

(1) 单点查询

单点就很简单啦,直接递归到叶子结点。对于非叶子结点,如果要查询节点\(x<=mid\)就去左端点找,否则去右端点找。

int ask(int k, int l, int r, int x)
{
	if(l == r && l == x)
		return tree[k];
	int mid = (l + r) >> 1;
	int ans = 0;
	if(x <= mid)
		ans += ask(ls(k), l, mid, x);
	else
		ans += ask(rs(k), mid + 1, r, x);
	return ans;
}

(2)区间查询

这里就稍微复杂一点,我么需要分两种情况。

首先,记当前区间为\([l,r]\),需要查询区间为\([x,y]\)

  1. 当前节点的区间被需要查询的区间完全覆盖\((x <= l && r <= y)\),那我们直接在答案上加上当前节点的值就好了。

2.当前节点所在区间没有没需要查询的区间完全覆盖,这时候,如果\(x <= mid\)我们就在左子节点寻找,如果\(y>mid\)就去右子节点寻找。

#define ll long long
ll query(ll k, ll l, ll r, ll x, ll y)
{
	if(x <= l && r <= y)
		return tree[k];
	ll mid = (l + r) >> 1;
	ll ans = 0;
	if(x <= mid)
		ans += query(ls(k), l, mid, x, y);
	if(y > mid)
		ans += query(rs(k), mid + 1, r , x, y);
	return ans;
}

完结撒花!!!

posted @ 2020-09-13 21:34  Starry___sky  阅读(190)  评论(1编辑  收藏  举报
Live2D