Leetcode 2569 Handling Sum Queries After Update
You are given two 0-indexed arrays nums1
and nums2
and a 2D array queries
of queries. There are three types of queries:
- For a query of type 1,
queries[i] = [1, l, r]
. Flip the values from0
to1
and from1
to0
innums1
from indexl
to indexr
. Bothl
andr
are 0-indexed. - For a query of type 2,
queries[i] = [2, p, 0]
. For every index0 <= i < n
, setnums2[i] = nums2[i] + nums1[i] * p
. - For a query of type 3,
queries[i] = [3, 0, 0]
. Find the sum of the elements innums2
.
Return an array containing all the answers to the third type queries.
Example 1:
Input: nums1 = [1,0,1], nums2 = [0,0,0], queries = [[1,1,1],[2,1,0],[3,0,0]] Output: [3] Explanation: After the first query nums1 becomes [1,1,1]. After the second query, nums2 becomes [1,1,1], so the answer to the third query is 3. Thus, [3] is returned.
Example 2:
Input: nums1 = [1], nums2 = [5], queries = [[2,0,0],[3,0,0]] Output: [5] Explanation: After the first query, nums2 remains [5], so the answer to the second query is 5. Thus, [5] is returned.
Constraints:
1 <= nums1.length,nums2.length <= 105
nums1.length = nums2.length
1 <= queries.length <= 105
queries[i].length = 3
0 <= l <= r <= nums1.length - 1
0 <= p <= 106
0 <= nums1[i] <= 1
0 <= nums2[i] <= 109
Problem Description:
There are two arrays, num1 and num2. num1 contains only 0s and 1s, while num2 contains integers. There are three operations: Operation 1: Choose a range, and reverse the 0s and 1s in the range of num1. Operation 2: Add each element of num1 to the corresponding index of num2. Operation 3: Return the sum of num2 and record the answer.
Problem Analysis:
When encountering a problem with range operations, we need to analyze the scope of each modification and query. We find that for num1, we need to perform range modification and sum query. For num2, we only need to return its sum. In this case, we can use a segment tree to maintain num1. As for num2, since it will not be modified in a range, only globally modified, we only need to record its sum. For each operation, we simply add the sum of num1 to the sum of num2. Because:
∑num1[i]+num2[i] = ∑num1[i]+∑num2[i]
Therefore, we only need to use a segment tree to maintain the range modification and sum query of num1[i], which is the range query. We can use a lazyTag segment tree to achieve this. However, there are some details to be handled: 1. The sum of the current node must be the number of "1"s in the represented range, and the number of "0"s in the range is naturally the range length minus the number of "1"s. When an update is required after a reversal, we only need to let tree.sum = tree.length - tree.sum, because the original 0s have become 1s, and the sum is naturally the number of 1s; 2. When updating lazyTag, if it is already equal to 1, there is no need to change it to 2, but rather change it to 0, because reversing twice is equivalent to no reversal at all.
题目大意:
题意是有两个数组,num1和num2,num1是只有0/1,num2存的int。有三个操作:操作1:选择一个区间,将num1的这个区间的0/1反转;操作2:将num1的每个数加到对应下标的num2上;操作3:返回num2的和,记录答案。
题目解析:
看到区间操作的题目,先要分析每次修改和查询的范围。我们发现对于num1,我们需要的是区间修改,总和查询。而对于num2,我们只需要返回它的总和。那么这种情况就可以考虑线段树维护num1。而对于num2,因为它不会被区间修改,只会整体修改,那么我们只需要记录它的总和,对于每一次操作直接将num2的总和加上num1的总和就好了。因为:
∑num1[i]+num2[i] = ∑num1[i]+∑num2[i]
由此可见我们只需要用线段树维护num1[i]的区间修改和总和查询,也就是区间查询。我们可以使用lazyTage的线段树来实现这一点。但是有一些细节需要处理:1,所以当前节点的和,一定是当前节点所表示区间的“1”的个数,那么这个区间“0”的个数自然是区间长度减去“1”的个数。当经过一次反转,需要进行更新时,只需要让tree.sum = tree.lenghth - tree.sum就可以了,因为原先的0都变成了1,那么和自然是1的个数; 2, lazyTag更新时,如果原本已经等于1了,就不需要变成2,而是变成0,因为反转两次等于没有反转嘛。
根据这些,写出代码:
class Solution { public: vector<long long> handleQuery(vector<int>& nums1, vector<int>& nums2, vector<vector<int>>& queries) { build(0, nums1.size() - 1, 0, nums1); vector<long long> ans; long long sum = 0; for (int i : nums2) { sum += i; } for (vector<int> query : queries) { int a, b, c; a = query[0]; b = query[1]; c = query[2]; if (a == 1) { add(0, b, c); } else if (a == 2) { sum += (long long)find() * b; } else { ans.push_back(sum); } } return ans; } private: const int N = 1e5 + 5; struct node { int leftRange, rightRange; int sum, lazyTag; }tree[400010]; int left(int index) { return index * 2 + 1; } int right(int index) { return index * 2 + 2; } void build(int leftRange, int rightRange, int index, vector<int>& input) { tree[index].sum = 0; tree[index].leftRange = leftRange; tree[index].rightRange = rightRange; if (leftRange == rightRange) { tree[index].sum = input[leftRange]; return; } int mid = (leftRange + rightRange) >> 1; build(leftRange, mid, left(index), input); build(mid + 1, rightRange, right(index), input); tree[index].sum = tree[left(index)].sum + tree[right(index)].sum; } void pushDown(int index) { if (!tree[index].lazyTag) { return; } tree[left(index)].lazyTag = !tree[left(index)].lazyTag; tree[right(index)].lazyTag = !tree[right(index)].lazyTag; tree[left(index)].sum = (tree[left(index)].rightRange - tree[left(index)].leftRange + 1) - tree[left(index)].sum; tree[right(index)].sum = (tree[right(index)].rightRange - tree[right(index)].leftRange + 1) - tree[right(index)].sum; tree[index].lazyTag = 0; } void add(int index, int leftRange, int rightRange) { if (tree[index].leftRange >= leftRange && tree[index].rightRange <= rightRange) { tree[index].sum = tree[index].rightRange - tree[index].leftRange + 1 - tree[index].sum; tree[index].lazyTag = tree[index].lazyTag ? 0 : 1; return; } pushDown(index); if (tree[left(index)].rightRange >= leftRange) { add(left(index), leftRange, rightRange); } if (tree[right(index)].leftRange <= rightRange) { add(right(index), leftRange, rightRange); } tree[index].sum = tree[left(index)].sum + tree[right(index)].sum; } int find() { return tree[0].sum; } };