100388. 交替组 III
给你一个整数数组 colors
和一个二维整数数组 queries
。colors
表示一个由红色和蓝色瓷砖组成的环,第 i
块瓷砖的颜色为 colors[i]
:
colors[i] == 0
表示第 i
块瓷砖的颜色是 红色 。colors[i] == 1
表示第 i
块瓷砖的颜色是 蓝色 。环中连续若干块瓷砖的颜色如果是 交替 颜色(也就是说这组瓷砖中除了第一块和最后一块瓷砖以外,中间瓷砖的颜色与它 左边 和 右边 的颜色都不同),那么它被称为一个 交替组。
你需要处理两种类型的查询:
queries[i] = [1, sizei]
,确定大小为sizei
的 交替组 的数量。queries[i] = [2, indexi, colori]
,将colors[indexi]
更改为colori
。返回数组 answer
,数组中按顺序包含第一种类型查询的结果。
注意 ,由于 colors
表示一个 环 ,第一块 瓷砖和 最后一块 瓷砖是相邻的。
示例 1:
输入:colors = [0,1,1,0,1], queries = [[2,1,0],[1,4]]
输出:[2]
解释:
第一次查询:
将 colors[1]
改为 0。
第二次查询:
统计大小为 4 的交替组的数量:
示例 2:
输入:colors = [0,0,1,0,1,1], queries = [[1,3],[2,3,0],[1,5]]
输出:[2,0]
解释:
第一次查询:
统计大小为 3 的交替组的数量。
第二次查询:colors
不变。
第三次查询:不存在大小为 5 的交替组。
提示:
4 <= colors.length <= 5 * 104
0 <= colors[i] <= 1
1 <= queries.length <= 5 * 104
queries[i][0] == 1
或 queries[i][0] == 2
i
:
queries[i][0] == 1
: queries[i].length == 2
, 3 <= queries[i][1] <= colors.length - 1
queries[i][0] == 2
: queries[i].length == 3
, 0 <= queries[i][1] <= colors.length - 1
, 0 <= queries[i][2] <= 1
原站题解
cpp 解法, 执行用时: 369 ms, 内存消耗: 174.1 MB, 提交时间: 2024-08-10 12:04:24
class FenwickTree { vector<array<int, 2>> tree; public: FenwickTree(int n) : tree(n + 1) {} // op=1,添加一个 size // op=-1,移除一个 size void update(int size, int op) { for (int i = tree.size() - size; i < tree.size(); i += i & -i) { tree[i][0] += op; tree[i][1] += op * size; } } // 返回 >= size 的元素个数,元素和 pair<int, int> query(int size) { int cnt = 0, sum = 0; for (int i = tree.size() - size; i > 0; i &= i - 1) { cnt += tree[i][0]; sum += tree[i][1]; } return {cnt, sum}; } }; class Solution { public: vector<int> numberOfAlternatingGroups(vector<int>& a, vector<vector<int>>& queries) { int n = a.size(); set<int> s; FenwickTree t(n); // op=1,添加一个结束位置 i // op=-1,移除一个结束位置 i auto update = [&](int i, int op) { auto it = s.lower_bound(i); int pre = it == s.begin() ? *s.rbegin() : *prev(it); int nxt = it == s.end() ? *s.begin() : *it; t.update((nxt - pre + n - 1) % n + 1, -op); // 移除/添加旧长度 t.update((i - pre + n) % n, op); t.update((nxt - i + n) % n, op); // 添加/移除新长度 }; // 添加一个结束位置 i auto add = [&](int i) { if (s.empty()) { t.update(n, 1); } else { update(i, 1); } s.insert(i); }; // 移除一个结束位置 i auto del = [&](int i) { s.erase(i); if (s.empty()) { t.update(n, -1); } else { update(i, -1); } }; for (int i = 0; i < n; i++) { if (a[i] == a[(i + 1) % n]) { add(i); // i 是一个结束位置 } } vector<int> ans; for (auto& q : queries) { if (q[0] == 1) { if (s.empty()) { ans.push_back(n); // 每个长为 size 的子数组都符合要求 } else { auto [cnt, sum] = t.query(q[1]); ans.push_back(sum - cnt * (q[1] - 1)); } } else { int i = q[1]; if (a[i] == q[2]) { // 无影响 continue; } int pre = (i - 1 + n) % n, nxt = (i + 1) % n; // 修改前,先去掉结束位置 if (a[pre] == a[i]) { del(pre); } if (a[i] == a[nxt]) { del(i); } a[i] ^= 1; // 修改后,添加新的结束位置 if (a[pre] == a[i]) { add(pre); } if (a[i] == a[nxt]) { add(i); } } } return ans; } };
golang 解法, 执行用时: 431 ms, 内存消耗: 15.6 MB, 提交时间: 2024-08-10 12:04:00
type fenwickTree [][2]int // op=1,添加一个 size // op=-1,移除一个 size func (t fenwickTree) update(size, op int) { for i := len(t) - size; i < len(t); i += i & -i { t[i][0] += op t[i][1] += op * size } } // 返回 >= size 的元素个数,元素和 func (t fenwickTree) query(size int) (cnt, sum int) { for i := len(t) - size; i > 0; i &= i - 1 { cnt += t[i][0] sum += t[i][1] } return } func numberOfAlternatingGroups(a []int, queries [][]int) (ans []int) { n := len(a) set := redblacktree.New[int, struct{}]() t := make(fenwickTree, n+1) // op=1,添加一个结束位置 i // op=-1,移除一个结束位置 i update := func(i, op int) { prev, ok := set.Floor(i) if !ok { prev = set.Right() } pre := prev.Key next, ok := set.Ceiling(i) if !ok { next = set.Left() } nxt := next.Key t.update((nxt-pre+n-1)%n+1, -op) // 移除/添加旧长度 t.update((i-pre+n)%n, op) t.update((nxt-i+n)%n, op) // 添加/移除新长度 } // 添加一个结束位置 i add := func(i int) { if set.Empty() { t.update(n, 1) } else { update(i, 1) } set.Put(i, struct{}{}) } // 移除一个结束位置 i del := func(i int) { set.Remove(i) if set.Empty() { t.update(n, -1) } else { update(i, -1) } } for i, c := range a { if c == a[(i+1)%n] { add(i) // i 是一个结束位置 } } for _, q := range queries { if q[0] == 1 { if set.Empty() { ans = append(ans, n) // 每个长为 size 的子数组都符合要求 } else { cnt, sum := t.query(q[1]) ans = append(ans, sum-cnt*(q[1]-1)) } } else { i := q[1] if a[i] == q[2] { // 无影响 continue } pre, nxt := (i-1+n)%n, (i+1)%n // 修改前,先去掉结束位置 if a[pre] == a[i] { del(pre) } if a[i] == a[nxt] { del(i) } a[i] ^= 1 // 修改后,添加新的结束位置 if a[pre] == a[i] { add(pre) } if a[i] == a[nxt] { add(i) } } } return }
java 解法, 执行用时: 100 ms, 内存消耗: 79.4 MB, 提交时间: 2024-08-10 12:03:45
class FenwickTree { private final int[][] t; public FenwickTree(int n) { t = new int[n + 1][2]; } // op=1,添加一个 size // op=-1,移除一个 size public void update(int size, int op) { for (int i = t.length - size; i < t.length; i += i & -i) { t[i][0] += op; t[i][1] += op * size; } } // 返回 >= size 的元素个数,元素和 public int[] query(int size) { int cnt = 0, sum = 0; for (int i = t.length - size; i > 0; i &= i - 1) { cnt += t[i][0]; sum += t[i][1]; } return new int[]{cnt, sum}; } } class Solution { public List<Integer> numberOfAlternatingGroups(int[] a, int[][] queries) { int n = a.length; TreeSet<Integer> set = new TreeSet<>(); FenwickTree t = new FenwickTree(n); for (int i = 0; i < n; i++) { if (a[i] == a[(i + 1) % n]) { add(set, t, n, i); // i 是一个结束位置 } } List<Integer> ans = new ArrayList<>(); for (int[] q : queries) { if (q[0] == 1) { if (set.isEmpty()) { ans.add(n); // 每个长为 size 的子数组都符合要求 } else { int[] res = t.query(q[1]); ans.add(res[1] - res[0] * (q[1] - 1)); } } else { int i = q[1]; if (a[i] == q[2]) { // 无影响 continue; } int pre = (i - 1 + n) % n; int nxt = (i + 1) % n; // 修改前,先去掉结束位置 if (a[pre] == a[i]) { del(set, t, n, pre); } if (a[i] == a[nxt]) { del(set, t, n, i); } a[i] ^= 1; // 修改后,添加新的结束位置 if (a[pre] == a[i]) { add(set, t, n, pre); } if (a[i] == a[nxt]) { add(set, t, n, i); } } } return ans; } // 添加一个结束位置 i private void add(TreeSet<Integer> set, FenwickTree t, int n, int i) { if (set.isEmpty()) { t.update(n, 1); } else { update(set, t, n, i, 1); } set.add(i); } // 移除一个结束位置 i private void del(TreeSet<Integer> set, FenwickTree t, int n, int i) { set.remove(i); if (set.isEmpty()) { t.update(n, -1); } else { update(set, t, n, i, -1); } } // op=1,添加一个结束位置 i // op=-1,移除一个结束位置 i private void update(TreeSet<Integer> set, FenwickTree t, int n, int i, int op) { Integer pre = set.floor(i); if (pre == null) { pre = set.last(); } Integer nxt = set.ceiling(i); if (nxt == null) { nxt = set.first(); } t.update((nxt - pre + n - 1) % n + 1, -op); // 移除/添加旧长度 t.update((i - pre + n) % n, op); t.update((nxt - i + n) % n, op); // 添加/移除新长度 } }
python3 解法, 执行用时: 1202 ms, 内存消耗: 36.2 MB, 提交时间: 2024-08-10 12:03:31
from sortedcontainers import SortedList class Solution: def numberOfAlternatingGroups(self, a: List[int], queries: List[List[int]]) -> List[int]: n = len(a) sl = SortedList() t = [[0, 0] for _ in range(n + 1)] # op=1,添加一个 size # op=-1,移除一个 size def fenwick_update(size: int, op: int) -> None: i = len(t) - size while i < len(t): t[i][0] += op t[i][1] += op * size i += i & -i # 返回 >= size 的元素个数,元素和 def fenwick_query(size: int) -> (int, int): cnt = s = 0 i = len(t) - size while i > 0: cnt += t[i][0] s += t[i][1] i &= i - 1 return cnt, s # op=1,添加一个结束位置 i # op=-1,移除一个结束位置 i def update(i: int, op: int) -> None: idx = sl.bisect_left(i) pre = sl[idx - 1] nxt = sl[idx % len(sl)] fenwick_update((nxt - pre - 1) % n + 1, -op) # 移除/添加旧长度 fenwick_update((i - pre) % n, op) fenwick_update((nxt - i) % n, op) # 添加/移除新长度 # 添加一个结束位置 i def add(i: int) -> None: if not sl: fenwick_update(n, 1) else: update(i, 1) sl.add(i) # 移除一个结束位置 i def remove(i: int) -> None: sl.remove(i) if not sl: fenwick_update(n, -1) else: update(i, -1) for i, c in enumerate(a): if c == a[(i + 1) % n]: add(i) # i 是一个结束位置 ans = [] for q in queries: if q[0] == 1: if not sl: ans.append(n) # 每个长为 size 的子数组都符合要求 else: cnt, s = fenwick_query(q[1]) ans.append(s - cnt * (q[1] - 1)) else: i, c = q[1], q[2] if a[i] == c: # 无影响 continue pre, nxt = (i - 1) % n, (i + 1) % n # 修改前,先去掉结束位置 if a[pre] == a[i]: remove(pre) if a[i] == a[nxt]: remove(i) a[i] = c # 修改后,添加新的结束位置 if a[pre] == a[i]: add(pre) if a[i] == a[nxt]: add(i) return ans
python3 解法, 执行用时: 1386 ms, 内存消耗: 36.2 MB, 提交时间: 2024-08-10 12:03:18
from sortedcontainers import SortedList class FenwickTree: def __init__(self, n: int): self.t = [[0, 0] for _ in range(n + 1)] # op=1,添加一个 size # op=-1,移除一个 size def update(self, size: int, op: int) -> None: i = len(self.t) - size while i < len(self.t): self.t[i][0] += op self.t[i][1] += op * size i += i & -i # 返回 >= size 的元素个数,元素和 def query(self, size: int) -> (int, int): cnt = s = 0 i = len(self.t) - size while i > 0: cnt += self.t[i][0] s += self.t[i][1] i &= i - 1 return cnt, s class Solution: def numberOfAlternatingGroups(self, a: List[int], queries: List[List[int]]) -> List[int]: n = len(a) sl = SortedList() t = FenwickTree(n) # op=1,添加一个结束位置 i # op=-1,移除一个结束位置 i def update(i: int, op: int) -> None: idx = sl.bisect_left(i) pre = sl[idx - 1] nxt = sl[idx % len(sl)] t.update((nxt - pre - 1) % n + 1, -op) # 移除/添加旧长度 t.update((i - pre) % n, op) t.update((nxt - i) % n, op) # 添加/移除新长度 # 添加一个结束位置 i def add(i: int) -> None: if not sl: t.update(n, 1) else: update(i, 1) sl.add(i) # 移除一个结束位置 i def remove(i: int) -> None: sl.remove(i) if not sl: t.update(n, -1) else: update(i, -1) for i, c in enumerate(a): if c == a[(i + 1) % n]: add(i) # i 是一个结束位置 ans = [] for q in queries: if q[0] == 1: if not sl: ans.append(n) # 每个长为 size 的子数组都符合要求 else: cnt, s = t.query(q[1]) ans.append(s - cnt * (q[1] - 1)) else: i, c = q[1], q[2] if a[i] == c: # 无影响 continue pre, nxt = (i - 1) % n, (i + 1) % n # 修改前,先去掉结束位置 if a[pre] == a[i]: remove(pre) if a[i] == a[nxt]: remove(i) a[i] = c # 修改后,添加新的结束位置 if a[pre] == a[i]: add(pre) if a[i] == a[nxt]: add(i) return ans