Question - 5
Segment trees are extremely useful. In particular "Lazy Propagation" (i.e. see here, for example) allows one to compute sums over a range in O(lg(n)), and update ranges in O(lg(n)) as well. In this problem you will compute something much harder:
The sum of squares over a range with range updates of 2 types:
1) increment in a range
2) set all numbers the same in a range.
Input
There will be T (T <= 25) test cases in the input file. First line of the input contains two positive integers, N (N <= 100,000) and Q (Q <= 100,000).
The next line contains N integers, each at most 1000. Each of the next Q lines starts with a number, which indicates the type of operation:
2 st nd -- return the sum of the squares of the numbers with indices in [st, nd] {i.e., from st to nd inclusive} (1 <= st <= nd <= N).
1 st nd x -- add "x" to all numbers with indices in [st, nd] (1 <= st <= nd <= N, and -1,000 <= x <= 1,000).
0 st nd x -- set all numbers with indices in [st, nd] to "x" (1 <= st <= nd <= N, and -1,000 <= x <= 1,000).
Output
For each test case output the “Case <caseno>:” in the first line and from the second line output the sum of squares for each operation of type 2. Intermediate overflow will not occur with proper use of 64-bit signed integer.
Input:
2
4 5
1 2 3 4
2 1 4
0 3 4 1
2 1 4
1 3 4 1
2 1 4
1 1
1
2 1 1
Output:
Case 1:
30
7
13
Case 2:
1
class Main {
static class TreeNode {
int sum, sq_sum;
TreeNode(int sum, int sq_sum) {
this.sum = sum;
this.sq_sum = sq_sum;
}
}
static class LazyNode {
// type : 0-> shows that no action is needed , 1-> shows that increment is needed,
// 2-> replacement is needed
int type, value;
LazyNode(int type, int value) {
this.type = type;
this.value = value;
}
}
public static void helper(TreeNode[] tree, LazyNode[] lazy, int start, int end, int index) {
if (lazy[index].type == 1) {
tree[index].sq_sum += (lazy[index].value * lazy[index].value * (end - start + 1))
+ (2 * lazy[index].value * tree[index].sum);
tree[index].sum += lazy[index].value * (end - start + 1);
if (start != end) {
lazy[2 * index] = new LazyNode(1, lazy[2 * index].value + lazy[index].value);
lazy[2 * index + 1] = new LazyNode(1, lazy[2 * index + 1].value + lazy[index].value);
}
} else {
tree[index].sq_sum = (end - start + 1) * lazy[index].value * lazy[index].value;
tree[index].sum = (end - start + 1) * lazy[index].value;
if (start != end) {
lazy[2 * index] = new LazyNode(2, lazy[index].value);
lazy[2 * index + 1] = new LazyNode(2, lazy[index].value);
}
}
lazy[index] = new LazyNode(0, 0);
}
// building the lazy tree aswell with its default values
public static void build(int[] arr, TreeNode[] tree, LazyNode[] lazy, int start, int end, int index) {
if (start == end) {
tree[index] = new TreeNode(arr[start], arr[start] * arr[start]);
lazy[index] = new LazyNode(0, 0); // default values
return;
}
int mid = (start + end) / 2;
build(arr, tree, lazy, start, mid, 2 * index);
build(arr, tree, lazy, mid + 1, end, 2 * index + 1);
tree[index] = new TreeNode(tree[2 * index].sum + tree[2 * index + 1].sum,
tree[2 * index].sq_sum + tree[2 * index + 1].sq_sum);
lazy[index] = new LazyNode(0, 0);// default values
}
public static void update(TreeNode[] tree, LazyNode[] lazy, int start, int end, int index, int L, int R, int value,
int type) {
if (lazy[index].type != 0)
helper(tree, lazy, start, end, index);
// no overlap
if (start > R || end < L)
return;
// complete overlap
if (start >= L && end <= R) {
if (type == 1) {
tree[index].sq_sum += 2 * value * tree[index].sum + (value * value * (end - start + 1));
tree[index].sum += value * (end - start + 1);
if (start != end) {
lazy[2 * index] = new LazyNode(1, lazy[2 * index].value + value);
lazy[2 * index + 1] = new LazyNode(1, lazy[2 * index + 1].value + value);
}
} else {
tree[index].sq_sum = value * value * (end - start + 1);
tree[index].sum = value * (end - start + 1);
if (start != end) {
lazy[2 * index] = new LazyNode(2, value);
lazy[2 * index + 1] = new LazyNode(2, value);
}
}
return;
}
// partial overlap
int mid = (start + end) / 2;
update(tree, lazy, start, mid, 2 * index, L, R, value, type);
update(tree, lazy, mid + 1, end, 2 * index + 1, L, R, value, type);
tree[index].sq_sum = tree[2 * index].sq_sum + tree[2 * index + 1].sq_sum;
tree[index].sum = tree[2 * index].sum + tree[2 * index + 1].sum;
}
public static TreeNode printQuery(TreeNode[] tree, LazyNode[] lazy, int start, int end, int index, int l, int r) {
// no overlap
if (start > r || end < l)
return new TreeNode(0, 0);
if (lazy[index].type != 0)
helper(tree, lazy, start, end, index);
// complete overlap
if (start >= l && end <= r)
return tree[index];
// partial overlap
int mid = (start + end) / 2;
TreeNode leftAns = printQuery(tree, lazy, start, mid, 2 * index, l, r);
TreeNode rightAns = printQuery(tree, lazy, mid + 1, end, 2 * index + 1, l, r);
return new TreeNode(leftAns.sum + rightAns.sum, leftAns.sq_sum + rightAns.sq_sum);
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int t = s.nextInt();
for (int j = 1; j <= t; j++) {
int n = s.nextInt(), q = s.nextInt();
int arr[] = new int[n];
for (int i = 0; i < n; i++)
arr[i] = s.nextInt();
TreeNode[] tree = new TreeNode[4 * n];
LazyNode[] lazy = new LazyNode[4 * n];
build(arr, tree, lazy, 0, n - 1, 1);
System.out.println("Case " + j + ":");
while (q-- > 0) {
int type = s.nextInt();
int st = s.nextInt() - 1;
int nd = s.nextInt() - 1;
if (type == 2)
System.out.println(printQuery(tree, lazy, 0, n - 1, 1, st, nd).sq_sum);
else {
int x = s.nextInt();
if (type == 1)
update(tree, lazy, 0, n - 1, 1, st, nd, x, 1);
else
update(tree, lazy, 0, n - 1, 1, st, nd, x, 2);
}
}
}
s.close();
}
}
Last updated