0%

2569.更新数组后处理求和查询

线段树

image-20230726230118723

2569. 更新数组后处理求和查询

给你两个下标从 0 开始的数组 nums1nums2 ,和一个二维数组 queries 表示一些操作。总共有 3 种类型的操作:

  1. 操作类型 1 为 queries[i] = [1, l, r] 。你需要将 nums1 从下标 l 到下标 r 的所有 0 反转成 1 或将 1 反转成 0lr 下标都从 0 开始。
  2. 操作类型 2 为 queries[i] = [2, p, 0] 。对于 0 <= i < n 中的所有下标,令 nums2[i] = nums2[i] + nums1[i] * p
  3. 操作类型 3 为 queries[i] = [3, 0, 0] 。求 nums2 中所有元素的和。

请你返回一个数组,包含所有第三种操作类型的答案。

示例 1:

输入:nums1 = [1,0,1], nums2 = [0,0,0], queries = [[1,1,1],[2,1,0],[3,0,0]]
输出:[3]
解释:第一个操作后 nums1 变为 [1,1,1] 。第二个操作后,nums2 变成 [1,1,1] ,所以第三个操作的答案为 3 。所以返回 [3]

示例 2:

输入:nums1 = [1], nums2 = [5], queries = [[2,0,0],[3,0,0]]
输出:[5]
解释:第一个操作后,nums2 保持不变为 [5] ,所以第二个操作的答案是 5 。所以返回 [5]

提示:

  • 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

C++

思路:线段树

image-20230726225711323

class Node {
public:
int l = 0, r = 0;
int s = 0, lazy = 0;
};

class SegmentTree {
public:
SegmentTree(vector<int>& nums) {
this->nums = nums;
int n = nums.size();
tr.resize(n << 2);
for (int i = 0; i < tr.size(); ++i) {
tr[i] = new Node();
}
build(1, 1, n);
}

void modify(int u, int l, int r) {
if (tr[u]->l >= l && tr[u]->r <= r) {
tr[u]->lazy ^= 1;
tr[u]->s = tr[u]->r - tr[u]->l + 1 - tr[u]->s;
return;
}
pushdown(u);
int mid = (tr[u]->l + tr[u]->r) >> 1;
if (l <= mid) {
modify(u << 1, l, r);
}
if (r > mid) {
modify(u << 1 | 1, l, r);
}
pushup(u);
}

int query(int u, int l, int r) {
if (tr[u]->l >= l && tr[u]->r <= r) {
return tr[u]->s;
}
pushdown(u);
int mid = (tr[u]->l + tr[u]->r) >> 1;
int res = 0;
if (l <= mid) {
res += query(u << 1, l, r);
}
if (r > mid) {
res += query(u << 1 | 1, l, r);
}
return res;
}

private:
vector<Node*> tr;
vector<int> nums;

void build(int u, int l, int r) {
tr[u]->l = l;
tr[u]->r = r;
if (l == r) {
tr[u]->s = nums[l - 1];
return;
}
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}

void pushup(int u) {
tr[u]->s = tr[u << 1]->s + tr[u << 1 | 1]->s;
}

void pushdown(int u) {
if (tr[u]->lazy) {
int mid = (tr[u]->l + tr[u]->r) >> 1;
tr[u << 1]->s = mid - tr[u]->l + 1 - tr[u << 1]->s;
tr[u << 1]->lazy ^= 1; // 将 tr[u << 1] 对象的 lazy 属性与 1 进行异或操作,相当于取反
tr[u << 1 | 1]->s = tr[u]->r - mid - tr[u << 1 | 1]->s; // 将 u 的二进制表示向左移动一位,然后将结果与二进制数 1 进行按位或操作
tr[u << 1 | 1]->lazy ^= 1;
tr[u]->lazy ^= 1;
}
}
};

class Solution {
public:
vector<long long> handleQuery(vector<int>& nums1, vector<int>& nums2, vector<vector<int>>& queries) {
SegmentTree* tree = new SegmentTree(nums1);
long long s = 0;
for (int& x : nums2) {
s += x;
}
vector<long long> ans;
for (auto& q : queries) {
if (q[0] == 1) {
tree->modify(1, q[1] + 1, q[2] + 1);
} else if (q[0] == 2) {
s += 1LL * q[1] * tree->query(1, 1, nums1.size());
} else {
ans.push_back(s);
}
}
return ans;
}
};