Skip to content

Commit 016779e

Browse files
committed
Improved task 3245
1 parent 23d0cf8 commit 016779e

File tree

1 file changed

+135
-212
lines changed
  • src/main/java/g3201_3300/s3245_alternating_groups_iii

1 file changed

+135
-212
lines changed
Lines changed: 135 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,245 +1,168 @@
11
package g3201_3300.s3245_alternating_groups_iii;
22

3-
// #Hard #Array #Binary_Indexed_Tree #2024_08_06_Time_36_ms_(82.22%)_Space_70.3_MB_(97.78%)
3+
// #Hard #Array #Binary_Indexed_Tree #2025_02_12_Time_135_ms_(86.36%)_Space_84.24_MB_(40.91%)
44

55
import java.util.ArrayList;
66
import java.util.List;
7+
import java.util.Map;
8+
import java.util.TreeMap;
79

810
public class Solution {
9-
private void go(int ind, LST lst, int[] fs, int n, LST ff, int[] c) {
10-
if (ind > 0) {
11-
int pre = lst.prev(ind - 1);
12-
int nex = lst.next(pre + 1);
13-
if (nex == -1) {
14-
nex = 2 * n;
15-
}
16-
if (pre != -1 && pre < n && --fs[nex - pre] == 0) {
17-
ff.unsetPos(nex - pre);
18-
}
19-
}
20-
if (lst.get(ind)) {
21-
int pre = ind;
22-
int nex = lst.next(ind + 1);
23-
if (nex == -1) {
24-
nex = 2 * n;
25-
}
26-
if (pre != -1 && pre < n && --fs[nex - pre] == 0) {
27-
ff.unsetPos(nex - pre);
28-
}
29-
}
30-
if (lst.get(ind + 1)) {
31-
int pre = ind + 1;
32-
int nex = lst.next(ind + 2);
33-
if (nex == -1) {
34-
nex = 2 * n;
35-
}
36-
if (pre != -1 && pre < n && --fs[nex - pre] == 0) {
37-
ff.unsetPos(nex - pre);
38-
}
39-
}
40-
lst.unsetPos(ind);
41-
lst.unsetPos(ind + 1);
42-
c[ind] ^= 1;
43-
if (ind > 0 && c[ind] != c[ind - 1]) {
44-
lst.setPos(ind);
45-
}
46-
if (ind + 1 < c.length && c[ind + 1] != c[ind]) {
47-
lst.setPos(ind + 1);
48-
}
49-
if (ind > 0) {
50-
int pre = lst.prev(ind - 1);
51-
int nex = lst.next(pre + 1);
52-
if (nex == -1) {
53-
nex = 2 * n;
54-
}
55-
if (pre != -1 && pre < n && ++fs[nex - pre] == 1) {
56-
ff.setPos(nex - pre);
11+
private static final int SZ = 63333;
12+
private static final int OFFSET = SZ - 10;
13+
private static final BIT[] BITS = {new BIT(), new BIT()};
14+
15+
// Class to represent the Binary Indexed Tree (BIT)
16+
private static class BIT {
17+
int[] bs = new int[SZ];
18+
19+
// Update BIT: add value y to index x
20+
void update(int x, int y) {
21+
x = OFFSET - x;
22+
for (; x < SZ; x += x & -x) {
23+
bs[x] += y;
5724
}
5825
}
59-
if (lst.get(ind)) {
60-
int pre = ind;
61-
int nex = lst.next(ind + 1);
62-
if (nex == -1) {
63-
nex = 2 * n;
64-
}
65-
if (pre < n && ++fs[nex - pre] == 1) {
66-
ff.setPos(nex - pre);
26+
27+
// Query BIT: get the prefix sum up to index x
28+
int query(int x) {
29+
x = OFFSET - x;
30+
int ans = 0;
31+
for (; x > 0; x -= x & -x) {
32+
ans += bs[x];
6733
}
34+
return ans;
6835
}
69-
if (lst.get(ind + 1)) {
70-
int pre = ind + 1;
71-
int nex = lst.next(ind + 2);
72-
if (nex == -1) {
73-
nex = 2 * n;
74-
}
75-
if (pre < n && ++fs[nex - pre] == 1) {
76-
ff.setPos(nex - pre);
36+
37+
// Clear BIT values up to index x
38+
void clear(int x) {
39+
x = OFFSET - x;
40+
for (; x < SZ; x += x & -x) {
41+
bs[x] = 0;
7742
}
7843
}
7944
}
8045

46+
// Wrapper functions for updating and querying the BITs
47+
private void edt(int x, int y) {
48+
// Update second BIT with product of index and value
49+
BITS[1].update(x, x * y);
50+
// Update first BIT with value
51+
BITS[0].update(x, y);
52+
}
53+
54+
private int qry(int x) {
55+
// Query BITs and combine results
56+
return BITS[1].query(x) + (1 - x) * BITS[0].query(x);
57+
}
58+
59+
// Function to calculate the length between two indices
60+
private int len(int x, int y) {
61+
return y - x + 1;
62+
}
63+
64+
// Main function to handle the queries
8165
public List<Integer> numberOfAlternatingGroups(int[] colors, int[][] queries) {
66+
// Map to store start and end indices of alternating groups
67+
TreeMap<Integer, Integer> c = new TreeMap<>();
8268
int n = colors.length;
83-
int[] c = new int[2 * n];
84-
for (int i = 0; i < 2 * n; i++) {
85-
c[i] = colors[i % n] ^ (i % 2 == 0 ? 0 : 1);
86-
}
87-
LST lst = new LST(2 * n + 3);
88-
for (int i = 1; i < 2 * n; i++) {
89-
if (c[i] != c[i - 1]) {
90-
lst.setPos(i);
91-
}
92-
}
93-
int[] fs = new int[2 * n + 1];
94-
LST ff = new LST(2 * n + 1);
95-
for (int i = 0; i < n; i++) {
96-
if (lst.get(i)) {
97-
int ne = lst.next(i + 1);
98-
if (ne == -1) {
99-
ne = 2 * n;
100-
}
101-
fs[ne - i]++;
102-
ff.setPos(ne - i);
103-
}
104-
}
105-
List<Integer> ans = new ArrayList<>();
69+
// Initialize alternating groups
70+
for (int i = 0; i < colors.length; ++i) {
71+
int r = i;
72+
// Find end of the current alternating group
73+
while (r < colors.length && (colors[r] + colors[i] + r + i) % 2 == 0) {
74+
++r;
75+
}
76+
// Store group boundaries in map
77+
c.put(i, r - 1);
78+
// Update BITs with new group
79+
edt(r - i, 1);
80+
// Move to the end of the current group
81+
i = r - 1;
82+
}
83+
// List to store results for type 1 queries
84+
List<Integer> results = new ArrayList<>();
85+
// Process each query
10686
for (int[] q : queries) {
10787
if (q[0] == 1) {
108-
if (lst.next(0) == -1) {
109-
ans.add(n);
110-
} else {
111-
int lans = 0;
112-
for (int i = ff.next(q[1]); i != -1; i = ff.next(i + 1)) {
113-
lans += (i - q[1] + 1) * fs[i];
88+
// Query type 1: Count alternating groups of a given size
89+
int ans = qry(q[1]);
90+
Map.Entry<Integer, Integer> a = c.firstEntry();
91+
Map.Entry<Integer, Integer> b = c.lastEntry();
92+
if (a != b) {
93+
// Check if merging groups is possible
94+
if (colors[0] != colors[colors.length - 1]) {
95+
int l1 = len(a.getKey(), a.getValue());
96+
int l2 = len(b.getKey(), b.getValue());
97+
// Subtract groups that are too small
98+
ans -= Math.max(l1 - q[1] + 1, 0);
99+
ans -= Math.max(l2 - q[1] + 1, 0);
100+
// Add merged group size
101+
ans += Math.max(l1 + l2 - q[1] + 1, 0);
114102
}
115-
if (c[2 * n - 1] != c[0]) {
116-
int f = lst.next(0);
117-
if (f >= q[1]) {
118-
lans += (f - q[1] + 1);
119-
}
120-
}
121-
ans.add(lans);
103+
} else if (colors[0] != colors[colors.length - 1]) {
104+
// If there's only one group, check if it can span the entire array
105+
ans = n;
122106
}
107+
// Store result for type 1 query
108+
results.add(ans);
123109
} else {
124-
int ind = q[1];
125-
int val = q[2];
126-
if (colors[ind] == val) {
110+
// Query type 2: Update color at a given index
111+
int x = q[1];
112+
int y = q[2];
113+
if (colors[x] == y) {
114+
// If color is already correct, skip update
127115
continue;
128116
}
129-
colors[ind] ^= 1;
130-
go(ind, lst, fs, n, ff, c);
131-
go(ind + n, lst, fs, n, ff, c);
132-
}
133-
}
134-
return ans;
135-
}
136-
137-
private static class LST {
138-
private long[][] set;
139-
private int n;
140-
141-
public LST(int n) {
142-
this.n = n;
143-
int d = 1;
144-
d = getD(n, d);
145-
set = new long[d][];
146-
for (int i = 0, m = n >>> 6; i < d; i++, m >>>= 6) {
147-
set[i] = new long[m + 1];
148-
}
149-
}
150-
151-
private int getD(int n, int d) {
152-
int m = n;
153-
while (m > 1) {
154-
m >>>= 6;
155-
d++;
156-
}
157-
return d;
158-
}
159-
160-
public LST setPos(int pos) {
161-
if (pos >= 0 && pos < n) {
162-
for (int i = 0; i < set.length; i++, pos >>>= 6) {
163-
set[i][pos >>> 6] |= 1L << pos;
164-
}
165-
}
166-
return this;
167-
}
168-
169-
public LST unsetPos(int pos) {
170-
if (pos >= 0 && pos < n) {
171-
for (int i = 0;
172-
i < set.length && (i == 0 || set[i - 1][pos] == 0L);
173-
i++, pos >>>= 6) {
174-
set[i][pos >>> 6] &= ~(1L << pos);
175-
}
176-
}
177-
return this;
178-
}
179-
180-
public boolean get(int pos) {
181-
return pos >= 0 && pos < n && set[0][pos >>> 6] << ~pos < 0;
182-
}
183-
184-
public int prev(int pos) {
185-
int i = 0;
186-
while (i < set.length && pos >= 0) {
187-
int pre = prev(set[i][pos >>> 6], pos & 63);
188-
if (pre != -1) {
189-
pos = pos >>> 6 << 6 | pre;
190-
while (i > 0) {
191-
pos = pos << 6 | 63 - Long.numberOfLeadingZeros(set[--i][pos]);
117+
// Update color
118+
colors[x] = y;
119+
// Find the block containing index x
120+
Map.Entry<Integer, Integer> it = c.floorEntry(x);
121+
assert it != null && it.getKey() <= x && it.getValue() >= x;
122+
int l = it.getKey();
123+
int r = it.getValue();
124+
// Remove the old block
125+
edt(len(it.getKey(), it.getValue()), -1);
126+
c.remove(it.getKey());
127+
int ml = x;
128+
int mr = x;
129+
// Update or split the affected blocks
130+
if (l != ml) {
131+
c.put(l, x - 1);
132+
edt(len(l, x - 1), 1);
133+
} else {
134+
if (x > 0 && colors[x] != colors[x - 1]) {
135+
it = c.floorEntry(x - 1);
136+
if (it != null) {
137+
ml = it.getKey();
138+
edt(len(it.getKey(), it.getValue()), -1);
139+
c.remove(it.getKey());
140+
}
192141
}
193-
return pos;
194142
}
195-
i++;
196-
pos >>>= 6;
197-
pos--;
198-
}
199-
return -1;
200-
}
201-
202-
private int prev(long set, int n) {
203-
long h = set << ~n;
204-
if (h == 0L) {
205-
return -1;
206-
}
207-
return -Long.numberOfLeadingZeros(h) + n;
208-
}
209-
210-
public int next(int pos) {
211-
int i = 0;
212-
while (i < set.length && pos >>> 6 < set[i].length) {
213-
int nex = next(set[i][pos >>> 6], pos & 63);
214-
if (nex != -1) {
215-
pos = pos >>> 6 << 6 | nex;
216-
while (i > 0) {
217-
pos = pos << 6 | Long.numberOfTrailingZeros(set[--i][pos]);
143+
if (r != mr) {
144+
c.put(x + 1, r);
145+
edt(len(x + 1, r), 1);
146+
} else {
147+
if (x + 1 < colors.length && colors[x + 1] != colors[x]) {
148+
it = c.ceilingEntry(x + 1);
149+
if (it != null) {
150+
mr = it.getValue();
151+
edt(len(it.getKey(), it.getValue()), -1);
152+
c.remove(it.getKey());
153+
}
218154
}
219-
return pos;
220155
}
221-
i++;
222-
pos >>>= 6;
223-
pos++;
224-
}
225-
return -1;
226-
}
227-
228-
private static int next(long set, int n) {
229-
long h = set >>> n;
230-
if (h == 0L) {
231-
return -1;
156+
c.put(ml, mr);
157+
// Add new or modified block
158+
edt(len(ml, mr), 1);
232159
}
233-
return Long.numberOfTrailingZeros(h) + n;
234160
}
235-
236-
@Override
237-
public String toString() {
238-
List<Integer> list = new ArrayList<>();
239-
for (int pos = next(0); pos != -1; pos = next(pos + 1)) {
240-
list.add(pos);
241-
}
242-
return list.toString();
161+
// Clear BITs after processing all queries
162+
for (int i = 0; i <= n + 2; ++i) {
163+
BITS[0].clear(i);
164+
BITS[1].clear(i);
243165
}
166+
return results;
244167
}
245168
}

0 commit comments

Comments
 (0)