Approach
Sorting and greedy selection
For ABC341 E — Alternating String, the implementation first exposes a useful order, then scans that order while making locally justified choices.
- Choose the key that reveals the greedy or grouping structure.
- Sort the relevant records by that key.
- Scan in order, maintaining the invariant that makes each local choice safe.
Code notes
- 227 lines of Python from the credited upstream file abc341_e.py.
- The implementation visibly relies on sequence storage, ordered lookup.
- No explicit loop blocks detected.
Complexity
Sorting is typically the dominant term unless the subsequent scan uses a more expensive nested operation.
Check the problem constraints before deciding whether this complexity will pass.
Use this to learn the idea, then write your own version.
12 3import math4from bisect import bisect_left, bisect_right5from typing import Generic, Iterable, Iterator, List, TypeVar, Union6 7T = TypeVar("T")8 9 10class SortedSet(Generic[T]):11 """Sorted set (set) in C++.12 13 See:14 https:qiita.com/tatyam/items/492c70ac4c955c05560215 https:github.com/tatyam-prime/SortedSet/blob/main/SortedSet.py16 """17 18 BUCKET_RATIO = 5019 REBUILD_RATIO = 17020 21 def _build(self, a=None) -> None:22 "Evenly divide `a` into buckets."23 if a is None:24 a = list(self)25 26 size = self.size = len(a)27 bucket_size = int(math.ceil(math.sqrt(size / self.BUCKET_RATIO)))28 self.a = [29 a[size * i bucket_size : size * (i + 1) bucket_size]30 for i in range(bucket_size)31 ]32 33 def __init__(self, a: Iterable[T] = []) -> None:34 """Make a new SortedSet from iterable.35 / O(N) if sorted and unique / O(N log N)36 """37 a = list(a)38 39 if not all(a[i] < a[i + 1] for i in range(len(a) - 1)): 40 a = sorted(set(a)) 41 42 self._build(a)43 44 def __iter__(self) -> Iterator[T]:45 for i in self.a:46 for j in i:47 yield j 48 49 def __reversed__(self) -> Iterator[T]:50 for i in reversed(self.a):51 for j in reversed(i):52 yield j53 54 def __len__(self) -> int:55 return self.size56 57 def __repr__(self) -> str:58 return "SortedSet" + str(self.a)59 60 def __str__(self) -> str:61 s = str(list(self))62 return "{" + s[1 : len(s) - 1] + "}"63 64 def _find_bucket(self, x: T) -> List[T]:65 "Find the bucket which should contain x. self must not be empty."66 for a in self.a:67 if x <= a[-1]: 68 return a69 return a70 71 def __contains__(self, x: T) -> bool:72 if self.size == 0:73 return False74 75 a = self._find_bucket(x)76 i = bisect_left(a, x) 77 78 return i != len(a) and a[i] == x79 80 def add(self, x: T) -> bool:81 "Add an element and return True if added. / O(√N)"82 if self.size == 0:83 self.a = [[x]]84 self.size = 185 return True86 87 a = self._find_bucket(x)88 i = bisect_left(a, x) 89 90 if i != len(a) and a[i] == x:91 return False92 93 a.insert(i, x)94 self.size += 195 96 if len(a) > len(self.a) * self.REBUILD_RATIO:97 self._build()98 99 return True100 101 def discard(self, x: T) -> bool:102 "Remove an element and return True if removed. / O(√N)"103 if self.size == 0:104 return False105 106 a = self._find_bucket(x)107 i = bisect_left(a, x) 108 109 if i == len(a) or a[i] != x:110 return False111 112 a.pop(i)113 self.size -= 1114 115 if len(a) == 0:116 self._build()117 return True118 119 def lt(self, x: T) -> Union[T, None]:120 "Find the largest element < x, or None if it doesn't exist."121 for a in reversed(self.a):122 if a[0] < x: 123 return a[bisect_left(a, x) - 1] 124 return None125 126 def le(self, x: T) -> Union[T, None]:127 "Find the largest element <= x, or None if it doesn't exist."128 for a in reversed(self.a):129 if a[0] <= x: 130 return a[bisect_right(a, x) - 1] 131 return None132 133 def gt(self, x: T) -> Union[T, None]:134 "Find the smallest element > x, or None if it doesn't exist."135 for a in self.a:136 if a[-1] > x: 137 return a[bisect_right(a, x)] 138 return None139 140 def ge(self, x: T) -> Union[T, None]:141 "Find the smallest element >= x, or None if it doesn't exist."142 for a in self.a:143 if a[-1] >= x: 144 return a[bisect_left(a, x)] 145 return None146 147 def __getitem__(self, x: int) -> T:148 "Return the x-th element, or IndexError if it doesn't exist."149 if x < 0:150 x += self.size151 if x < 0:152 raise IndexError153 154 for a in self.a:155 if x < len(a):156 return a[x] 157 158 x -= len(a)159 raise IndexError160 161 def index(self, x: T) -> int:162 "Count the number of elements < x."163 ans = 0164 165 for a in self.a:166 if a[-1] >= x: 167 return ans + bisect_left(a, x) 168 ans += len(a)169 return ans170 171 def index_right(self, x: T) -> int:172 "Count the number of elements <= x."173 ans = 0174 175 for a in self.a:176 if a[-1] > x: 177 return ans + bisect_right(a, x) 178 ans += len(a)179 return ans180 181 182def main():183 import sys184 185 input = sys.stdin.readline186 187 n, q = map(int, input().split())188 s = input().rstrip()189 t = SortedSet()190 191 192 193 for i in range(n - 1):194 if s[i] == s[i + 1]:195 t.add(i + 1)196 197 198 inf = 10**9199 t.add(inf)200 201 for _ in range(q):202 type, li, ri = map(int, input().split())203 204 if type == 1:205 li -= 1206 207 if li in t:208 t.discard(li)209 else:210 t.add(li)211 212 if ri in t:213 t.discard(ri)214 else:215 t.add(ri)216 else:217 value = t.ge(li)218 219 if value < ri:220 print("No")221 else:222 print("Yes")223 224 225if __name__ == "__main__":226 main()227