线段树的构建和查询
(本系列函数参数表示为\(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]\)
- 当前节点的区间被需要查询的区间完全覆盖\((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;
}
完结撒花!!!