题目描述
给你两个下标从 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:
输入: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
解法
方法一:线段树
根据题目描述:
- 操作 $1$ 是把数组
nums1
的下标区间 $[l,..r]$ 的所有数反转,即把 $0$ 变成 $1$,把 $1$ 变成 $0$。
- 操作 $3$ 是求数组
nums2
的所有数之和。
- 操作 $2$ 是把数组
nums2
的所有数之和加上 $p$ 乘以数组 nums1
所有数之和,即 $sum(nums2) = sum(nums2) + p * sum(nums1)$。
因此,我们实际上只需要维护数组 nums1
的区间和即可,我们可以通过线段树来实现。
我们定义线段树的每个节点为 Node
,每个节点包含如下属性:
l
:节点的左端点,下标从 $1$ 开始。
r
:节点的右端点,下标从 $1$ 开始。
s
:节点的区间和。
lazy
:节点的懒标记。
线段树主要有以下几个操作:
build(u, l, r)
:建立线段树。
pushdown(u)
:下传懒标记。
pushup(u)
:用子节点的信息更新父节点的信息。
modify(u, l, r)
:修改区间和,本题中是反转区间中的每个数,那么区间和 $s = r - l + 1 - s$。
query(u, l, r)
:查询区间和。
我们先算出数组 nums2
的所有数之和,记为 $s$。
执行操作 $1$ 时,我们只需要调用 modify(1, l + 1, r + 1)
即可。
执行操作 $2$ 时,我们更新 $s = s + p \times query(1, 1, n)$ 即可。
执行操作 $3$ 时,我们只需要将 $s$ 加入答案数组即可。
时间复杂度 $O(n + m \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别为数组 nums1
和 queries
的长度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 | class Node:
def __init__(self):
self.l = self.r = 0
self.s = self.lazy = 0
class SegmentTree:
def __init__(self, nums):
self.nums = nums
n = len(nums)
self.tr = [Node() for _ in range(n << 2)]
self.build(1, 1, n)
def build(self, u, l, r):
self.tr[u].l, self.tr[u].r = l, r
if l == r:
self.tr[u].s = self.nums[l - 1]
return
mid = (l + r) >> 1
self.build(u << 1, l, mid)
self.build(u << 1 | 1, mid + 1, r)
self.pushup(u)
def modify(self, u, l, r):
if self.tr[u].l >= l and self.tr[u].r <= r:
self.tr[u].lazy ^= 1
self.tr[u].s = self.tr[u].r - self.tr[u].l + 1 - self.tr[u].s
return
self.pushdown(u)
mid = (self.tr[u].l + self.tr[u].r) >> 1
if l <= mid:
self.modify(u << 1, l, r)
if r > mid:
self.modify(u << 1 | 1, l, r)
self.pushup(u)
def query(self, u, l, r):
if self.tr[u].l >= l and self.tr[u].r <= r:
return self.tr[u].s
self.pushdown(u)
mid = (self.tr[u].l + self.tr[u].r) >> 1
res = 0
if l <= mid:
res += self.query(u << 1, l, r)
if r > mid:
res += self.query(u << 1 | 1, l, r)
return res
def pushup(self, u):
self.tr[u].s = self.tr[u << 1].s + self.tr[u << 1 | 1].s
def pushdown(self, u):
if self.tr[u].lazy:
mid = (self.tr[u].l + self.tr[u].r) >> 1
self.tr[u << 1].s = mid - self.tr[u].l + 1 - self.tr[u << 1].s
self.tr[u << 1].lazy ^= 1
self.tr[u << 1 | 1].s = self.tr[u].r - mid - self.tr[u << 1 | 1].s
self.tr[u << 1 | 1].lazy ^= 1
self.tr[u].lazy ^= 1
class Solution:
def handleQuery(
self, nums1: List[int], nums2: List[int], queries: List[List[int]]
) -> List[int]:
tree = SegmentTree(nums1)
s = sum(nums2)
ans = []
for op, a, b in queries:
if op == 1:
tree.modify(1, a + 1, b + 1)
elif op == 2:
s += a * tree.query(1, 1, len(nums1))
else:
ans.append(s)
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 | class Node {
int l, r;
int s, lazy;
}
class SegmentTree {
private Node[] tr;
private int[] nums;
public SegmentTree(int[] nums) {
int n = nums.length;
this.nums = nums;
tr = new Node[n << 2];
for (int i = 0; i < tr.length; ++i) {
tr[i] = new Node();
}
build(1, 1, n);
}
private 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);
}
public 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);
}
public 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 void pushup(int u) {
tr[u].s = tr[u << 1].s + tr[u << 1 | 1].s;
}
private void pushdown(int u) {
if (tr[u].lazy == 1) {
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 | 1].s = tr[u].r - mid - tr[u << 1 | 1].s;
tr[u << 1 | 1].lazy ^= 1;
tr[u].lazy ^= 1;
}
}
}
class Solution {
public long[] handleQuery(int[] nums1, int[] nums2, int[][] queries) {
SegmentTree tree = new SegmentTree(nums1);
long s = 0;
for (int x : nums2) {
s += x;
}
int m = 0;
for (var q : queries) {
if (q[0] == 3) {
++m;
}
}
long[] ans = new long[m];
int i = 0;
for (var q : queries) {
if (q[0] == 1) {
tree.modify(1, q[1] + 1, q[2] + 1);
} else if (q[0] == 2) {
s += 1L * q[1] * tree.query(1, 1, nums2.length);
} else {
ans[i++] = s;
}
}
return ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 | 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 | 1]->s = tr[u]->r - mid - tr[u << 1 | 1]->s;
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;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 | type node struct {
l, r, s, lazy int
}
type segmentTree struct {
nums []int
tr []*node
}
func newSegmentTree(nums []int) *segmentTree {
n := len(nums)
tr := make([]*node, n<<2)
for i := range tr {
tr[i] = &node{}
}
t := &segmentTree{nums, tr}
t.build(1, 1, n)
return t
}
func (t *segmentTree) build(u, l, r int) {
t.tr[u].l, t.tr[u].r = l, r
if l == r {
t.tr[u].s = t.nums[l-1]
return
}
mid := (l + r) >> 1
t.build(u<<1, l, mid)
t.build(u<<1|1, mid+1, r)
t.pushup(u)
}
func (t *segmentTree) modify(u, l, r int) {
if t.tr[u].l >= l && t.tr[u].r <= r {
t.tr[u].lazy ^= 1
t.tr[u].s = t.tr[u].r - t.tr[u].l + 1 - t.tr[u].s
return
}
t.pushdown(u)
mid := (t.tr[u].l + t.tr[u].r) >> 1
if l <= mid {
t.modify(u<<1, l, r)
}
if r > mid {
t.modify(u<<1|1, l, r)
}
t.pushup(u)
}
func (t *segmentTree) query(u, l, r int) int {
if t.tr[u].l >= l && t.tr[u].r <= r {
return t.tr[u].s
}
t.pushdown(u)
mid := (t.tr[u].l + t.tr[u].r) >> 1
res := 0
if l <= mid {
res += t.query(u<<1, l, r)
}
if r > mid {
res += t.query(u<<1|1, l, r)
}
return res
}
func (t *segmentTree) pushup(u int) {
t.tr[u].s = t.tr[u<<1].s + t.tr[u<<1|1].s
}
func (t *segmentTree) pushdown(u int) {
if t.tr[u].lazy == 1 {
mid := (t.tr[u].l + t.tr[u].r) >> 1
t.tr[u<<1].s = mid - t.tr[u].l + 1 - t.tr[u<<1].s
t.tr[u<<1].lazy ^= 1
t.tr[u<<1|1].s = t.tr[u].r - mid - t.tr[u<<1|1].s
t.tr[u<<1|1].lazy ^= 1
t.tr[u].lazy ^= 1
}
}
func handleQuery(nums1 []int, nums2 []int, queries [][]int) (ans []int64) {
tree := newSegmentTree(nums1)
var s int64
for _, x := range nums2 {
s += int64(x)
}
for _, q := range queries {
if q[0] == 1 {
tree.modify(1, q[1]+1, q[2]+1)
} else if q[0] == 2 {
s += int64(q[1] * tree.query(1, 1, len(nums1)))
} else {
ans = append(ans, s)
}
}
return
}
|