Range Update Range Query
Authors: Benjamin Qi, Mihnea Brebenel, Justin Ji
Lazy updates on segment trees and two binary indexed trees in conjunction.
Prerequisites
BIT Revisited
Binary Indexed Trees can support range increments and range sum queries.
Resources
Focus Problem – try your best to solve this problem before continuing!
Explanation
First, we can reduce the problem of performing range add and range sum queries into an easier problem: adding on a suffix, and querying the sum of a prefix of our array.
Let our array be , and the prefix sum array of be . If we add to the range , then, for every , we add to each in the range. To query the prefix of , we can consider the following process:
- Find the sum of all the range additions affecting the index . Let this number be . For now, we evaluate their contribution to be equal to . We can keep track of all the range additions that affect each indice using a BIT.
- Step 1 obviously overcounts. To fix this overcounting, note that for each suffix addition query, the true contribution to the array only differs by a constant amount compared to the value obtained by step 1. This value is , if we update the suffix of by adding . Thus, we use a separate BIT that keeps track of all of the corrections to the contribution evaluated by step 1.
We can perform range addition and range summation queries by performing multiple suffix addition and prefix sum queries.
Implementation
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;Code Snippet: BIT Code (from PURS module) (Click to expand)int main() {int test_num;cin >> test_num;for (int t = 0; t < test_num; t++) {int n, q;
Problems
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
CSES | Easy | Show Tags1DRQ | |||
Baltic OI | Normal | Show Tags1DRQ, Binary Search | |||
IOI | Normal | Show Tags1DRQ, Binary Search |
Lazy Segment Tree
Lazy segment trees allow us to efficiently perform range updates and range queries.
Resources | ||||
---|---|---|---|---|
CF EDU | ||||
CPH | short description | |||
CSA | interactive | |||
cp-algo | adding on segments, assigning | |||
CF | code is more confusing than recursive version |
Lazy segment trees allow us to perform range updates and range queries in time. In order to perform range updates in , we lazily apply updates to the nodes. That is, we store updates on the nodes that compose the range we are updating, and lazily apply the updates when we walk down the tree.
As an example, let's consider writing a lazy segment tree that supports range addition and range summation. We would have our tree nodes contain the sum on the range, and keep a separate array keeping track of the lazy additions we have to do for each node. If we were to add to our array , then we would need to set a lazy update at the root of our tree indicating that we need to add to the entire range. Then, if we were to query a subarray of , we need to "push down" the updates at the root down to its children.
It is crucial that we always push down all the previous updates when traversing down the tree. If we don't, the following things can happen:
- If we have two updates that affect two nodes, where one node is an ancestor of another, then one of the updates will be ignored.
- The updates will be applied in incorrect order, which matters if the updates are not commutative.
For a concrete example for why point 1 can be an issue, consider the following sequence of updates.
- to all values on
- to all values on
- Query sum on
If we don't push down the updates when traversing down the tree, then the first update will get ignored in our sum query.
Horrible Queries Implementation
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;using ll = long long;template <typename T> class LazySegtree {private:const int sz;vector<T> tree;vector<T> lazy;
Focus Problem – try your best to solve this problem before continuing!
Explanation
This question asks you to support the following types of queries:
Add a value to all elements within the range .
Set all values within the range to a certain value.
Find the sum of all values in range .
Consider the first two types of queries. A lazy tag will be created in each node of the tree for each type. In this solution, will represent the lazy tag for the range add query and will represent the lazy tag for the range set query.
Given the two different types of update queries, a total of four different situations might take place after any update:
Range add when equals 0: Simply add the new value to the pre-existing value.
Range add when doesn't equal 0: Add the new value to and clear .
Range set when equals 0: Simply update the value.
Range set when doesn't equal 0: Again, simply update the value since a set update will override all previous add updates.
Given the mechanics behind the push_down
function, all you need is a regular
range-sum segment tree to solve the question.
Implementation
Time Complexity:
C++
#include <bits/stdc++.h>using namespace std;using ll = long long;/*** Represents the type of lazy update being done.* NONE = if there's no lazy update to be performed.*/enum QueryType { ADD, SET, NONE };
Lazy segment trees are notorious for being difficult to make generic. The AtCoder template is an example of a fully generic template.
Below is an implementation of the focus problem using a somewhat generic
template. The idea is that we supply an Info
and Tag
class into the template.
The Tag
class handles lazy updates, and how lazy updates interact with each other.
Meanwhile, the Info
class handles the tree values, and how lazy updates are applied
to given tree values.
Some key implementation details:
- We must give lazy tags and tree values neutral values. That is, we need to set the values inside the classes to some value that won't affect our answers.
- For the
apply
function in theInfo
andTag
functions, we need to ensure that we aren't applying neutral updates to any nodes.
C++
#include <bits/stdc++.h>using namespace std;using ll = long long;template <class Info, class Tag> class LazySegtree {private:const int n;vector<Info> tree;vector<Tag> lazy;
Problems
Status | Source | Problem Name | Difficulty | Tags | |
---|---|---|---|---|---|
YS | Easy | Show TagsLazy SegTree | |||
Platinum | Easy | Show TagsLazy SegTree | |||
CSES | Easy | Show TagsLazy SegTree | |||
Old Gold | Easy | Show TagsLazy SegTree | |||
IOI | Normal | Show TagsLazy SegTree | |||
IOI | Normal | Show TagsCoordinate Compression, Lazy SegTree | |||
Platinum | Normal | Show TagsEuler Tour, Lazy SegTree, PURS | |||
CF | Normal | Show TagsEuler Tour, RURQ | |||
JOI | Very Hard | Show TagsLazy SegTree | |||
DMOPC | Very Hard | Show TagsLazy SegTree |
Module Progress:
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!