Thus, it is necessary to effectively update the interval [L,R]with the corresponding values of the arithmetic progression in steps Xand to be able to efficiently find the sums at different intervals.
To solve this problem effectively, use the Lazy Segment Tree.
The main ideas are as follows:
, node :
class Node {
int left;
int right;
int sum;
int first;
int last;
Node left_child;
Node right_child;
Node(int[] arr, int l, int r) { ... }
void add(int l, int r, int X) { ... }
int query(int l, int r) { ... }
void propagate() { ... }
}
, , node - Lazy Propagation ( O (1)) node. , Lazy Propagation node, :

, Lazy Propagation first last , sum node.
Java ( ):
class Node {
int left;
int right;
int sum;
int first;
int last;
Node left_child;
Node right_child;
Node(int[] arr, int l, int r) {
left = l;
right = r;
if (l == r) {
sum = arr[l];
} else {
int m = (l + r) / 2;
left_child = new Node(arr, l, m);
right_child = new Node(arr, m + 1, r);
sum = left_child.sum + right_child.sum;
}
}
void add(int l, int r, int X) {
propagate();
if ((r < left) || (right < l)) {
return;
} else if ((l <= left) && (right <= r)) {
int first_item_offset = (left - l) + 1;
int last_item_offset = (right - l) + 1;
first = X * first_item_offset;
last = X * last_item_offset;
propagate();
} else {
left_child.add(l, r, X);
right_child.add(l, r, X);
sum = left_child.sum + right_child.sum;
}
}
int query(int l, int r) {
propagate();
if ((r < left) || (right < l)) {
return 0;
} else if ((l <= left) && (right <= r)) {
return sum;
} else {
return left_child.query(l, r) + right_child.query(l, r);
}
}
void propagate() {
int items_count = (right - left) + 1;
sum += ((first + last) * items_count) / 2;
if (right != left) {
int step = (last - first) / (items_count - 1);
int mid = (items_count - 1) / 2;
left_child.first += first;
left_child.last += first + (step * mid);
right_child.first += first + (step * (mid + 1));
right_child.last += last;
}
first = 0;
last = 0;
}
}
- , , .
, :
Java- :
public static void main(String[] args) {
Random rnd = new Random(1);
int test_cases_num = 20;
int max_arr_size = 100;
int num_queries = 50;
int max_progression_step = 20;
for (int test = 0; test < test_cases_num; test++) {
int[] arr = new int[rnd.nextInt(max_arr_size) + 1];
Node segmentTree = new Node(arr, 0, arr.length - 1);
for (int query = 0; query < num_queries; query++) {
if (rnd.nextDouble() < 0.5) {
int l = rnd.nextInt(arr.length);
int r = rnd.nextInt(arr.length - l) + l;
int X = rnd.nextInt(max_progression_step);
update_sequential(arr, l, r, X);
segmentTree.add(l, r, X);
}
else {
int l = rnd.nextInt(arr.length);
int r = rnd.nextInt(arr.length - l) + l;
int expected = query_sequential(arr, l, r);
int actual = segmentTree.query(l, r);
if (expected != actual) {
throw new RuntimeException("Results are different!");
}
}
}
}
System.out.println("All results are equal!");
}
static void update_sequential(int[] arr, int left, int right, int X) {
for (int i = left; i <= right; i++) {
arr[i] += X * ((i - left) + 1);
}
}
static int query_sequential(int[] arr, int left, int right) {
int sum = 0;
for (int i = left; i <= right; i++) {
sum += arr[i];
}
return sum;
}