更新数组后处理求和查询
给你两个下标从 0 开始的数组 nums1 和 nums2 ,和一个二维数组 queries 表示一些操作。总共有 3 种类型的操作:
- 操作类型 1 为 queries[i] = [1, l, r] 。你需要将 nums1 从下标 l 到下标 r 的所有 0 反转成 1 或将 1 反转成 0 。l 和 r 下标都从 0 开始。
- 操作类型 2 为 queries[i] = [2, p, 0] 。对于 0 <= i < n 中的所有下标,令 nums2[i] = nums2[i] + nums1[i] * p 。
- 操作类型 3 为 queries[i] = [3, 0, 0] 。求 nums2 中所有元素的和。
请你返回一个数组,包含所有第三种操作类型的答案。
1. 线段树 + 懒标记
线段树用于区间修改和区间求和
class Solution {
struct TreeNode {
int left; // 节点区间左边界
int right; // 节点区间右边界
int value; // 节点存储的信息,这里存储区间和
bool lazytag;//懒标记,不用每次修改区间,都去修改全部节点
};
public:
int n;
vector<TreeNode> tree;
void build(int index, int left, int right, const vector<int> &arr) {//初始化
tree[index].left = left;
tree[index].right = right;
tree[index].lazytag = false;
if (left == right) {
tree[index].value = arr[left];
return;
}
int mid = (left + right) / 2;
build(index * 2 + 1, left, mid, arr);//递归建左树,左节点对应左区间
build(index * 2 + 2, mid + 1, right, arr);//递归建右树,右节点对应右区间
tree[index].value = tree[index*2+1].value + tree[index*2+2].value;
}
int query(int index, int left, int right) {//查询
if (tree[index].left == left && tree[index].right == right)
return tree[index].value;
pushdown(index);//将查询区间的值进行更新
int mid = (tree[index].left + tree[index].right) / 2;
if (right <= mid)
return query(index * 2 + 1, left, mid);
else if (left > mid)
return query(index * 2 + 2, mid+1, right);
else
return query(index * 2 + 1, left, mid) + query(index * 2 + 2, mid+1, right);
}
void modify(int index, int left, int right) {
if (tree[index].left >= left && tree[index].right <= right) {//修改区间囊括当前节点
tree[index].value = (tree[index].right - tree[index].left + 1) - tree[index].value; //进行翻转,区间长度减去当前和
tree[index].lazytag = !tree[index].lazytag; //同时翻转懒标记
return;
}
pushdown(index);
int mid = (tree[index].left + tree[index].right) / 2;
if (right <= mid)
modify(index*2 + 1, left, right);
else if (left > mid)
modify(index*2 + 2, left, right);
else{
modify(index*2 + 1, left, right);
modify(index*2 + 2, left, right);
}
tree[index].value = tree[index*2 + 1].value + tree[index*2 + 2].value;
}
void pushdown(int index) {
if(tree[index].lazytag) {//该区间需要修改
tree[2*index+1].lazytag = !tree[2*index+1].lazytag;
tree[2*index+1].value = tree[2*index+1].right - tree[2*index+1].left + 1 - tree[2*index+1].value;
tree[2*index+2].lazytag = !tree[2*index+2].lazytag;
tree[2*index+2].value = tree[2*index+2].right - tree[2*index+2].left + 1 - tree[2*index+2].value;
tree[index].lazytag = false;
}
}
vector<long long> handleQuery(vector<int>& nums1, vector<int>& nums2, vector<vector<int>>& queries) {
//初始化线段树
n = nums1.size();
tree.resize(4*n);
build(0,0,n-1,nums1);
long long sum = accumulate(nums2.begin(), nums2.end(), 0LL);
vector<long long> ans;
for (int i = 0; i < queries.size(); i++) {
if (queries[i][0] == 1) {
int l = queries[i][1]; //左边界
int r = queries[i][2]; //右边界
modify(0, l, r); //翻转
} else if (queries[i][0] == 2) {
sum += (long long)query(0, 0, n - 1) * queries[i][1]; //统计1的个数,直接叠加到结果
} else if (queries[i][0] == 3) {
ans.emplace_back(sum);
}
}
return ans;
}
};