📅  最后修改于: 2023-12-03 15:37:13.920000             🧑  作者: Mango
给定一个长度为 n 的数组 a,其中 1 ≤ n ≤ 10^5,-10^9 ≤ a_i ≤ 10^9,你需要支持以下两种操作:
对于此题,我们需要支持区间修改和区间查询操作。对于支持动态区间查询操作的问题,经常可以采用线段树的方式进行解答。
我们可以首先建立一棵线段树,将所有数值保存在叶子结点中。初始化时,将所有叶子结点初始化为数组 a 中的值。每个非叶子结点保存的是其左右子节点的和和积,由此便可高效完成区间查询操作。
对于修改操作,我们需要从根节点开始,沿着树往下走,将受影响的节点的值修改为新值。对于每个节点上保存的区间,若其覆盖区间与修改区间不相交,则无需修改该区间内的值;若相交,则需要分别递归到其左右子节点上修改。修改结束后,我们需要重新对每个节点保存的值进行更新。
具体代码实现过程中,我们可以采用递归或非递归两种方式。此外,在建立线段树时,我们可以多申请一些节点以避免越界等问题。
下面是一个采用递归方式实现区间修改和查询的示例代码(使用 C++ 语言):
struct Node {
int l, r;
ll sum, mul;
} tree[N * 4 + 5];
void build(int p, int l, int r) {
tree[p].l = l, tree[p].r = r, tree[p].mul = 1;
if (l == r) {
tree[p].sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(p << 1, l, mid);
build(p << 1 | 1, mid + 1, r);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].mul = tree[p << 1].mul * tree[p << 1 | 1].mul;
}
void pushdown(int p) {
tree[p << 1].mul *= tree[p].mul;
tree[p << 1 | 1].mul *= tree[p].mul;
tree[p << 1].sum *= tree[p].mul;
tree[p << 1 | 1].sum *= tree[p].mul;
tree[p].mul = 1;
}
void update(int p, int x, ll k) {
if (tree[p].l == x && tree[p].r == x) {
tree[p].sum = k;
return;
}
pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if (x <= mid) update(p << 1, x, k);
if (x > mid) update(p << 1 | 1, x, k);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
}
void modify(int p, int l, int r, ll k) {
if (tree[p].l == l && tree[p].r == r) {
tree[p].mul *= k;
tree[p].sum *= k;
return;
}
pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if (r <= mid) modify(p << 1, l, r, k);
else if (l > mid) modify(p << 1 | 1, l, r, k);
else modify(p << 1, l, mid, k), modify(p << 1 | 1, mid + 1, r, k);
tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
tree[p].mul = tree[p << 1].mul * tree[p << 1 | 1].mul;
}
ll query_sum(int p, int l, int r) {
if (tree[p].l == l && tree[p].r == r) return tree[p].sum;
pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if (r <= mid) return query_sum(p << 1, l, r);
if (l > mid) return query_sum(p << 1 | 1, l, r);
return query_sum(p << 1, l, mid) + query_sum(p << 1 | 1, mid + 1, r);
}
ll query_mul(int p, int l, int r) {
if (tree[p].l == l && tree[p].r == r) return tree[p].mul;
pushdown(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if (r <= mid) return query_mul(p << 1, l, r);
if (l > mid) return query_mul(p << 1 | 1, l, r);
return query_mul(p << 1, l, mid) * query_mul(p << 1 | 1, mid + 1, r);
}
本题考察了对区间修改和查询操作的理解和实现能力。通过采用线段树的方式,我们能够高效地完成这些操作。对于其它涉及动态区间查询的问题,类似的思路也可以很好地进行拓展应用。