📜  在段树中不使用延迟传播和点查询的范围更新(1)

📅  最后修改于: 2023-12-03 15:08:03.788000             🧑  作者: Mango

在段树中不使用延迟传播和点查询的范围更新

在算法竞赛中,经常需要处理区间操作。其中最常用的数据结构便是线段树。但是,在实现的时候会遇到两个问题:延迟传播和点查询。

延迟传播是指,当对区间进行修改时,我们不一定要修改每一个叶子节点,而只修改总区间的一部分节点,对其余的节点打上一个标记,等到需要查询该区间时再修改。

点查询是指在查询区间和时,需要逐个查询每一个元素的值。

这两个问题虽然可以提高效率,但是代码复杂度也会增加。因此,我们可以考虑不使用延迟传播和点查询的方法来实现线段树。

实现思路

我们需要实现以下三个基本操作:build、update和query。其中,build操作用于初始化线段树;update用于对区间进行修改;query用于查询区间和。

build

在不使用延迟传播和点查询的线段树中,build操作可以直接递归地构建出线段树的每一个节点。

void build(int p, int l, int r) {
    if (l == r) {
        tree[p] = a[l];
        return;
    }
    int mid = (l + r) / 2;
    build(p * 2, l, mid);
    build(p * 2 + 1, mid + 1, r);
    tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
update

在不使用延迟传播的线段树中,我们需要递归地修改每一个与修改区间相交的节点。

void update(int p, int l, int r, int x, int y, int k) {
    if (x <= l && r <= y) {
        tree[p] += k * (r - l + 1);
        return;
    }
    int mid = (l + r) / 2;
    if (x <= mid) update(p * 2, l, mid, x, y, k);
    if (y > mid) update(p * 2 + 1, mid + 1, r, x, y, k);
    tree[p] = tree[p * 2] + tree[p * 2 + 1];
}
query

在不使用点查询的线段树中,我们需要递归地查询每一个与查询区间相交的节点,并返回它们的和。

int query(int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) {
        return tree[p];
    }
    int mid = (l + r) / 2;
    int sum = 0;
    if (x <= mid) sum += query(p * 2, l, mid, x, y);
    if (y > mid) sum += query(p * 2 + 1, mid + 1, r, x, y);
    return sum;
}
总结

不使用延迟传播和点查询的方法实现线段树,代码简单,易于理解。但是,由于对每一次修改和查询都需要递归地访问每一个相交的节点,因此效率较低。在面对数据范围较大的题目时,需要更高效的算法来完成。