dynamic_hash_string

ソースコード

from titan_pylib.string.dynamic_hash_string import DynamicHashStringBase
from titan_pylib.string.dynamic_hash_string import DynamicHashString

view on github

展開済みコード

  1# from titan_pylib.string.dynamic_hash_string import DynamicHashString
  2# ref: https://qiita.com/keymoon/items/11fac5627672a6d6a9f6
  3# from titan_pylib.data_structures.splay_tree.reversible_lazy_splay_tree_array import (
  4#     ReversibleLazySplayTreeArrayData,
  5#     ReversibleLazySplayTreeArray,
  6# )
  7from array import array
  8from typing import (
  9    Generic,
 10    TypeVar,
 11    Callable,
 12    Iterable,
 13    Optional,
 14    Union,
 15    Sequence,
 16)
 17
 18T = TypeVar("T")
 19F = TypeVar("F")
 20
 21
 22class ReversibleLazySplayTreeArrayData(Generic[T, F]):
 23
 24    def __init__(
 25        self,
 26        op: Optional[Callable[[T, T], T]] = None,
 27        mapping: Optional[Callable[[F, T], T]] = None,
 28        composition: Optional[Callable[[F, F], F]] = None,
 29        e: T = None,
 30        id: F = None,
 31    ) -> None:
 32        self.op: Callable[[T, T], T] = (lambda s, t: e) if op is None else op
 33        self.mapping: Callable[[F, T], T] = (lambda f, s: e) if op is None else mapping
 34        self.composition: Callable[[F, F], F] = (
 35            (lambda f, g: id) if op is None else composition
 36        )
 37        self.e: T = e
 38        self.id: F = id
 39        self.keydata: list[T] = [e, e, e]
 40        self.lazy: list[F] = [id]
 41        self.arr: array[int] = array("I", bytes(16))
 42        # left:  arr[node<<2]
 43        # right: arr[node<<2|1]
 44        # size:  arr[node<<2|2]
 45        # rev:   arr[node<<2|3]
 46        self.end: int = 1
 47
 48    def reserve(self, n: int) -> None:
 49        if n <= 0:
 50            return
 51        self.keydata += [self.e] * (3 * n)
 52        self.lazy += [self.id] * n
 53        self.arr += array("I", bytes(16 * n))
 54
 55
 56class ReversibleLazySplayTreeArray(Generic[T, F]):
 57
 58    def __init__(
 59        self,
 60        data: "ReversibleLazySplayTreeArrayData",
 61        n_or_a: Union[int, Iterable[T]] = 0,
 62        _root: int = 0,
 63    ):
 64        self.data = data
 65        self.root = _root
 66        if not n_or_a:
 67            return
 68        if isinstance(n_or_a, int):
 69            a = [data.e for _ in range(n_or_a)]
 70        elif not isinstance(n_or_a, Sequence):
 71            a = list(n_or_a)
 72        else:
 73            a = n_or_a
 74        if a:
 75            self._build(a)
 76
 77    def _build(self, a: Sequence[T]) -> None:
 78        def rec(l: int, r: int) -> int:
 79            mid = (l + r) >> 1
 80            if l != mid:
 81                arr[mid << 2] = rec(l, mid)
 82            if mid + 1 != r:
 83                arr[mid << 2 | 1] = rec(mid + 1, r)
 84            self._update(mid)
 85            return mid
 86
 87        n = len(a)
 88        keydata, arr = self.data.keydata, self.data.arr
 89        end = self.data.end
 90        self.data.reserve(n + end - len(keydata) // 3 + 1)
 91        self.data.end += n
 92        for i, e in enumerate(a):
 93            keydata[(end + i) * 3 + 0] = e
 94            keydata[(end + i) * 3 + 1] = e
 95            keydata[(end + i) * 3 + 2] = e
 96        self.root = rec(end, n + end)
 97
 98    def _make_node(self, key: T) -> int:
 99        data = self.data
100        if data.end >= len(data.arr) // 4:
101            data.keydata.append(key)
102            data.keydata.append(key)
103            data.keydata.append(key)
104            data.lazy.append(data.id)
105            data.arr.append(0)
106            data.arr.append(0)
107            data.arr.append(1)
108            data.arr.append(0)
109        else:
110            data.keydata[data.end * 3 + 0] = key
111            data.keydata[data.end * 3 + 1] = key
112            data.keydata[data.end * 3 + 2] = key
113        data.end += 1
114        return data.end - 1
115
116    def _propagate(self, node: int) -> None:
117        data = self.data
118        arr = data.arr
119        if arr[node << 2 | 3]:
120            keydata = data.keydata
121            keydata[node * 3 + 1], keydata[node * 3 + 2] = (
122                keydata[node * 3 + 2],
123                keydata[node * 3 + 1],
124            )
125            arr[node << 2], arr[node << 2 | 1] = arr[node << 2 | 1], arr[node << 2]
126            arr[node << 2 | 3] = 0
127            arr[arr[node << 2] << 2 | 3] ^= 1
128            arr[arr[node << 2 | 1] << 2 | 3] ^= 1
129        nlazy = data.lazy[node]
130        if nlazy == data.id:
131            return
132        lnode, rnode = arr[node << 2], arr[node << 2 | 1]
133        keydata, lazy = data.keydata, data.lazy
134        lazy[node] = data.id
135        if lnode:
136            lazy[lnode] = data.composition(nlazy, lazy[lnode])
137            keydata[lnode * 3 + 0] = data.mapping(nlazy, keydata[lnode * 3 + 0])
138            keydata[lnode * 3 + 1] = data.mapping(nlazy, keydata[lnode * 3 + 1])
139            keydata[lnode * 3 + 2] = data.mapping(nlazy, keydata[lnode * 3 + 2])
140        if rnode:
141            lazy[rnode] = data.composition(nlazy, lazy[rnode])
142            keydata[rnode * 3 + 0] = data.mapping(nlazy, keydata[rnode * 3 + 0])
143            keydata[rnode * 3 + 1] = data.mapping(nlazy, keydata[rnode * 3 + 1])
144            keydata[rnode * 3 + 2] = data.mapping(nlazy, keydata[rnode * 3 + 2])
145
146    def _update_triple(self, x: int, y: int, z: int) -> None:
147        # data = self.data
148        # keydata, arr = data.keydata, data.arr
149        # lx, rx = arr[x<<2], arr[x<<2|1]
150        # ly, ry = arr[y<<2], arr[y<<2|1]
151        # self._propagate(lx)
152        # self._propagate(rx)
153        # self._propagate(ly)
154        # self._propagate(ry)
155        # arr[z<<2|2] = arr[x<<2|2]
156        # arr[x<<2|2] = 1 + arr[lx<<2|2] + arr[rx<<2|2]
157        # arr[y<<2|2] = 1 + arr[ly<<2|2] + arr[ry<<2|2]
158        # keydata[z*3+1] = keydata[x*3+1]
159        # keydata[z*3+2] = keydata[x*3+2]
160        # keydata[x*3+1] = data.op(data.op(keydata[lx*3+1], keydata[x*3]), keydata[rx*3+1])
161        # keydata[x*3+2] = data.op(data.op(keydata[rx*3+2], keydata[x*3]), keydata[lx*3+2])
162        # keydata[y*3+1] = data.op(data.op(keydata[ly*3+1], keydata[y*3]), keydata[ry*3+1])
163        # keydata[y*3+2] = data.op(data.op(keydata[ry*3+2], keydata[y*3]), keydata[ly*3+2])
164        self._update(x)
165        self._update(y)
166        self._update(z)
167
168    def _update_double(self, x: int, y: int) -> None:
169        # data = self.data
170        # keydata, arr = data.keydata, data.arr
171        # lx, rx = arr[x<<2], arr[x<<2|1]
172        # self._propagate(lx)
173        # self._propagate(rx)
174        # arr[y<<2|2] = arr[x<<2|2]
175        # arr[x<<2|2] = 1 + arr[lx<<2|2] + arr[rx<<2|2]
176        # keydata[y*3+1] = keydata[x*3+1]
177        # keydata[y*3+2] = keydata[x*3+2]
178        # keydata[x*3+1] = data.op(data.op(keydata[lx*3+1], keydata[x*3]), keydata[rx*3+1])
179        # keydata[x*3+2] = data.op(data.op(keydata[rx*3+2], keydata[x*3]), keydata[lx*3+2])
180        self._update(x)
181        self._update(y)
182
183    def _update(self, node: int) -> None:
184        data = self.data
185        keydata, arr = data.keydata, data.arr
186        lnode, rnode = arr[node << 2], arr[node << 2 | 1]
187        self._propagate(lnode)
188        self._propagate(rnode)
189        arr[node << 2 | 2] = 1 + arr[lnode << 2 | 2] + arr[rnode << 2 | 2]
190        keydata[node * 3 + 1] = data.op(
191            data.op(keydata[lnode * 3 + 1], keydata[node * 3 + 0]),
192            keydata[rnode * 3 + 1],
193        )
194        keydata[node * 3 + 2] = data.op(
195            data.op(keydata[rnode * 3 + 2], keydata[node * 3 + 0]),
196            keydata[lnode * 3 + 2],
197        )
198
199    def _splay(self, path: list[int], d: int) -> None:
200        arr = self.data.arr
201        g = d & 1
202        while len(path) > 1:
203            pnode = path.pop()
204            gnode = path.pop()
205            f = d >> 1 & 1
206            node = arr[pnode << 2 | g ^ 1]
207            nnode = (pnode if g == f else node) << 2 | f
208            arr[pnode << 2 | g ^ 1] = arr[node << 2 | g]
209            arr[node << 2 | g] = pnode
210            arr[gnode << 2 | f ^ 1] = arr[nnode]
211            arr[nnode] = gnode
212            self._update_triple(gnode, pnode, node)
213            if not path:
214                return
215            d >>= 2
216            g = d & 1
217            arr[path[-1] << 2 | g ^ 1] = node
218        pnode = path.pop()
219        node = arr[pnode << 2 | g ^ 1]
220        arr[pnode << 2 | g ^ 1] = arr[node << 2 | g]
221        arr[node << 2 | g] = pnode
222        self._update_double(pnode, node)
223
224    def _kth_elm_splay(self, node: int, k: int) -> int:
225        arr = self.data.arr
226        if k < 0:
227            k += arr[node << 2 | 2]
228        d = 0
229        path = []
230        while True:
231            self._propagate(node)
232            t = arr[arr[node << 2] << 2 | 2]
233            if t == k:
234                if path:
235                    self._splay(path, d)
236                return node
237            d = d << 1 | (t > k)
238            path.append(node)
239            node = arr[node << 2 | (t < k)]
240            if t < k:
241                k -= t + 1
242
243    def _left_splay(self, node: int) -> int:
244        if not node:
245            return 0
246        self._propagate(node)
247        arr = self.data.arr
248        if not arr[node << 2]:
249            return node
250        path = []
251        while arr[node << 2]:
252            path.append(node)
253            node = arr[node << 2]
254            self._propagate(node)
255        self._splay(path, (1 << len(path)) - 1)
256        return node
257
258    def _right_splay(self, node: int) -> int:
259        if not node:
260            return 0
261        self._propagate(node)
262        arr = self.data.arr
263        if not arr[node << 2 | 1]:
264            return node
265        path = []
266        while arr[node << 2 | 1]:
267            path.append(node)
268            node = arr[node << 2 | 1]
269            self._propagate(node)
270        self._splay(path, 0)
271        return node
272
273    def reserve(self, n: int) -> None:
274        self.data.reserve(n)
275
276    def merge(self, other: "ReversibleLazySplayTreeArray") -> None:
277        assert self.data is other.data
278        if not other.root:
279            return
280        if not self.root:
281            self.root = other.root
282            return
283        self.root = self._right_splay(self.root)
284        self.data.arr[self.root << 2 | 1] = other.root
285        self._update(self.root)
286
287    def split(
288        self, k: int
289    ) -> tuple["ReversibleLazySplayTreeArray", "ReversibleLazySplayTreeArray"]:
290        assert (
291            -len(self) < k <= len(self)
292        ), f"IndexError: ReversibleLazySplayTreeArray.split({k}), len={len(self)}"
293        if k < 0:
294            k += len(self)
295        if k >= self.data.arr[self.root << 2 | 2]:
296            return self, ReversibleLazySplayTreeArray(self.data, _root=0)
297        self.root = self._kth_elm_splay(self.root, k)
298        left = ReversibleLazySplayTreeArray(
299            self.data, _root=self.data.arr[self.root << 2]
300        )
301        self.data.arr[self.root << 2] = 0
302        self._update(self.root)
303        return left, self
304
305    def _internal_split(self, k: int) -> tuple[int, int]:
306        if k >= self.data.arr[self.root << 2 | 2]:
307            return self.root, 0
308        self.root = self._kth_elm_splay(self.root, k)
309        left = self.data.arr[self.root << 2]
310        self._propagate(left)
311        self.data.arr[self.root << 2] = 0
312        self._update(self.root)
313        return left, self.root
314
315    def reverse(self, l: int, r: int) -> None:
316        assert (
317            0 <= l <= r <= len(self)
318        ), f"IndexError: ReversibleLazySplayTreeArray.reverse({l}, {r}), len={len(self)}"
319        if l == r:
320            return
321        data = self.data
322        left, right = self._internal_split(r)
323        if l:
324            left = self._kth_elm_splay(left, l - 1)
325        data.arr[(data.arr[left << 2 | 1] if l else left) << 2 | 3] ^= 1
326        if right:
327            data.arr[right << 2] = left
328            self._update(right)
329        self.root = right if right else left
330
331    def all_reverse(self) -> None:
332        self.data.arr[self.root << 2 | 3] ^= 1
333        self._propagate(self.root)
334
335    def apply(self, l: int, r: int, f: F) -> None:
336        assert (
337            0 <= l <= r <= len(self)
338        ), f"IndexError: ReversibleLazySplayTreeArray.apply({l}, {r}), len={len(self)}"
339        data = self.data
340        left, right = self._internal_split(r)
341        keydata, lazy = data.keydata, data.lazy
342        if l:
343            left = self._kth_elm_splay(left, l - 1)
344        node = data.arr[left << 2 | 1] if l else left
345        keydata[node * 3 + 0] = data.mapping(f, keydata[node * 3 + 0])
346        keydata[node * 3 + 1] = data.mapping(f, keydata[node * 3 + 1])
347        keydata[node * 3 + 2] = data.mapping(f, keydata[node * 3 + 2])
348        lazy[node] = data.composition(f, lazy[node])
349        if l:
350            self._update(left)
351        if right:
352            data.arr[right << 2] = left
353            self._update(right)
354        self.root = right if right else left
355
356    def all_apply(self, f: F) -> None:
357        if not self.root:
358            return
359        data, node = self.data, self.root
360        data.keydata[node * 3 + 0] = data.mapping(f, data.keydata[node * 3 + 0])
361        data.keydata[node * 3 + 1] = data.mapping(f, data.keydata[node * 3 + 1])
362        data.keydata[node * 3 + 2] = data.mapping(f, data.keydata[node * 3 + 2])
363        data.lazy[node] = data.composition(f, data.lazy[node])
364
365    def prod(self, l: int, r: int) -> T:
366        assert (
367            0 <= l <= r <= len(self)
368        ), f"IndexError: LazySplayTree.prod({l}, {r}), len={len(self)}"
369        data = self.data
370        left, right = self._internal_split(r)
371        if l:
372            left = self._kth_elm_splay(left, l - 1)
373        node = data.arr[left << 2 | 1] if l else left
374        self._propagate(node)
375        res = data.keydata[node * 3 + 1]
376        if right:
377            data.arr[right << 2] = left
378            self._update(right)
379        self.root = right if right else left
380        return res
381
382    def all_prod(self) -> T:
383        return self.data.keydata[self.root * 3 + 1]
384
385    def insert(self, k: int, key: T) -> None:
386        assert (
387            -len(self) <= k <= len(self)
388        ), f"IndexError: ReversibleLazySplayTreeArray.insert({k}, {key}), len={len(self)}"
389        if k < 0:
390            k += len(self)
391        data = self.data
392        node = self._make_node(key)
393        if not self.root:
394            self._update(node)
395            self.root = node
396            return
397        arr = data.arr
398        if k == data.arr[self.root << 2 | 2]:
399            arr[node << 2] = self._right_splay(self.root)
400        else:
401            node_ = self._kth_elm_splay(self.root, k)
402            if arr[node_ << 2]:
403                arr[node << 2] = arr[node_ << 2]
404                arr[node_ << 2] = 0
405                self._update(node_)
406            arr[node << 2 | 1] = node_
407        self._update(node)
408        self.root = node
409
410    def append(self, key: T) -> None:
411        data = self.data
412        node = self._right_splay(self.root)
413        self.root = self._make_node(key)
414        data.arr[self.root << 2] = node
415        self._update(self.root)
416
417    def appendleft(self, key: T) -> None:
418        node = self._left_splay(self.root)
419        self.root = self._make_node(key)
420        self.data.arr[self.root << 2 | 1] = node
421        self._update(self.root)
422
423    def pop(self, k: int = -1) -> T:
424        assert (
425            -len(self) <= k < len(self)
426        ), f"IndexError: ReversibleLazySplayTreeArray.pop({k})"
427        data = self.data
428        if k == -1:
429            node = self._right_splay(self.root)
430            self._propagate(node)
431            self.root = data.arr[node << 2]
432            return data.keydata[node * 3 + 0]
433        self.root = self._kth_elm_splay(self.root, k)
434        res = data.keydata[self.root * 3 + 0]
435        if not data.arr[self.root << 2]:
436            self.root = data.arr[self.root << 2 | 1]
437        elif not data.arr[self.root << 2 | 1]:
438            self.root = data.arr[self.root << 2]
439        else:
440            node = self._right_splay(data.arr[self.root << 2])
441            data.arr[node << 2 | 1] = data.arr[self.root << 2 | 1]
442            self.root = node
443            self._update(self.root)
444        return res
445
446    def popleft(self) -> T:
447        assert self, "IndexError: ReversibleLazySplayTreeArray.popleft()"
448        node = self._left_splay(self.root)
449        self.root = self.data.arr[node << 2 | 1]
450        return self.data.keydata[node * 3 + 0]
451
452    def rotate(self, x: int) -> None:
453        # 「末尾をを削除し先頭に挿入」をx回
454        n = self.data.arr[self.root << 2 | 2]
455        l, self = self.split(n - (x % n))
456        self.merge(l)
457
458    def tolist(self) -> list[T]:
459        node = self.root
460        arr, keydata = self.data.arr, self.data.keydata
461        stack = []
462        res = []
463        while stack or node:
464            if node:
465                self._propagate(node)
466                stack.append(node)
467                node = arr[node << 2]
468            else:
469                node = stack.pop()
470                res.append(keydata[node * 3 + 0])
471                node = arr[node << 2 | 1]
472        return res
473
474    def clear(self) -> None:
475        self.root = 0
476
477    def __setitem__(self, k: int, key: T):
478        assert (
479            -len(self) <= k < len(self)
480        ), f"IndexError: ReversibleLazySplayTreeArray.__setitem__({k})"
481        self.root = self._kth_elm_splay(self.root, k)
482        self.data.keydata[self.root * 3 + 0] = key
483        self._update(self.root)
484
485    def __getitem__(self, k: int) -> T:
486        assert (
487            -len(self) <= k < len(self)
488        ), f"IndexError: ReversibleLazySplayTreeArray.__getitem__({k})"
489        self.root = self._kth_elm_splay(self.root, k)
490        return self.data.keydata[self.root * 3 + 0]
491
492    def __iter__(self):
493        self.__iter = 0
494        return self
495
496    def __next__(self):
497        if self.__iter == self.data.arr[self.root << 2 | 2]:
498            raise StopIteration
499        res = self.__getitem__(self.__iter)
500        self.__iter += 1
501        return res
502
503    def __reversed__(self):
504        for i in range(len(self)):
505            yield self.__getitem__(-i - 1)
506
507    def __len__(self):
508        return self.data.arr[self.root << 2 | 2]
509
510    def __str__(self):
511        return str(self.tolist())
512
513    def __bool__(self):
514        return self.root != 0
515
516    def __repr__(self):
517        return f"ReversibleLazySplayTreeArray({self})"
518from typing import Optional, Final
519import random
520import string
521
522_titan_pylib_DynamicHashString_MOD: Final[int] = (1 << 61) - 1
523_titan_pylib_DynamicHashString_DIC: Final[dict[str, int]] = {
524    c: i for i, c in enumerate(string.ascii_lowercase, 1)
525}
526_titan_pylib_DynamicHashString_MASK30: Final[int] = (1 << 30) - 1
527_titan_pylib_DynamicHashString_MASK31: Final[int] = (1 << 31) - 1
528_titan_pylib_DynamicHashString_MASK61: Final[int] = _titan_pylib_DynamicHashString_MOD
529
530
531class DynamicHashStringBase:
532    """動的な文字列に対するロリハです。
533
534    平衡二分木にモノイドを載せてるだけです。こんなライブラリ必要ないです。
535
536    Example:
537        ```
538        base = DynamicHashStringBase(2 * 10**5 + 1)
539        dhs_s = DynamicHashString(base, s)
540        dhs_t = DynamicHashString(base, t)
541
542        pref = dhs_s.get(0, r)
543        suff = dhs_t.get(l, n)
544        h = base.unite(pref, suff, n-l)
545        ```
546    """
547
548    def __init__(self, n: int = 0, base: int = -1, seed: Optional[int] = None) -> None:
549        assert n >= 0
550        rand = random.Random(seed)
551        base = rand.randint(37, 10**9) if base < 0 else base
552        powb = [1] * (n + 1)
553        for i in range(1, n + 1):
554            powb[i] = self.get_mul(powb[i - 1], base)
555        op = lambda s, t: (self.unite(s[0], t[0], t[1]), s[1] + t[1])
556        e = (0, 0)
557        self.base = base
558        self.data = ReversibleLazySplayTreeArrayData(op=op, e=e)
559        self.n = n
560        self.powb = powb
561
562    @staticmethod
563    def get_mul(a: int, b: int) -> int:
564        au = a >> 31
565        ad = a & _titan_pylib_DynamicHashString_MASK31
566        bu = b >> 31
567        bd = b & _titan_pylib_DynamicHashString_MASK31
568        mid = ad * bu + au * bd
569        midu = mid >> 30
570        midd = mid & _titan_pylib_DynamicHashString_MASK30
571        return DynamicHashStringBase.get_mod(
572            au * bu * 2 + midu + (midd << 31) + ad * bd
573        )
574
575    @staticmethod
576    def get_mod(x: int) -> int:
577        # 商と余りを計算して足す->割る
578        xu = x >> 61
579        xd = x & _titan_pylib_DynamicHashString_MASK61
580        res = xu + xd
581        if res >= _titan_pylib_DynamicHashString_MOD:
582            res -= _titan_pylib_DynamicHashString_MOD
583        return res
584
585    def extend(self, cap: int) -> None:
586        pre_cap = len(self.powb)
587        powb = self.powb
588        powb += [0] * cap
589        for i in range(pre_cap, pre_cap + cap):
590            powb[i] = DynamicHashStringBase.get_mul(powb[i - 1], self.base)
591
592    def get_cap(self) -> int:
593        return len(self.powb)
594
595    def unite(self, h1: int, h2: int, k: int) -> int:
596        """2つの hash 値を concat します。
597
598        Args:
599            h1 (int): prefix
600            h2 (int): suffix
601            k (int): h2の長さ
602
603        Returns:
604            int: h1 + h2
605        """
606        # h1, h2, k
607        # len(h2) == k
608        # h1 <- h2
609        if k >= self.get_cap():
610            self.extend(k - self.get_cap() + 1)
611        return self.get_mod(self.get_mul(h1, self.powb[k]) + h2)
612
613
614class DynamicHashString:
615
616    def __init__(self, hsb: DynamicHashStringBase, s: str) -> None:
617        self.hsb = hsb
618        self.splay: ReversibleLazySplayTreeArray[tuple[int, int], None] = (
619            ReversibleLazySplayTreeArray(
620                hsb.data, ((_titan_pylib_DynamicHashString_DIC[c], 1) for c in s)
621            )
622        )
623
624    def insert(self, k: int, c: str) -> None:
625        """位置 ``k`` に ``c`` を挿入します。
626        :math:`O(\\log{n})` です。
627        """
628        self.splay.insert(k, (_titan_pylib_DynamicHashString_DIC[c], 1))
629
630    def pop(self, k: int) -> int:
631        return self.splay.pop(k)
632
633    def reverse(self, l: int, r: int) -> None:
634        self.splay.reverse(l, r)
635
636    def all_reverse(self) -> None:
637        self.splay.all_reverse()
638
639    def split(self, k: int) -> tuple["DynamicHashString", "DynamicHashString"]:
640        left, right = self.splay.split(k)
641        return (DynamicHashString(self.hsb, left), DynamicHashString(self.hsb, right))
642
643    def all_get(self) -> int:
644        return self.splay.all_prod()[0]
645
646    def get(self, l: int, r: int) -> int:
647        return self.splay.prod(l, r)[0]
648
649    def extend(self, other: "DynamicHashString") -> None:
650        assert self.hsb is other.hsb
651        self.splay.merge(other.splay)
652
653    def __getitem__(self, k: int) -> int:
654        return self.splay[k][0]
655
656    def set(self, k: int, c: str) -> None:
657        self.splay[k] = (_titan_pylib_DynamicHashString_DIC[c], 1)
658
659    def __setitem__(self, k: int, c: str) -> None:
660        return self.set(k, c)
661
662    def __len__(self) -> int:
663        return len(self.splay)
664
665    def __str__(self) -> str:
666        return str([self[i] for i in range(len(self))])

仕様

class DynamicHashString(hsb: DynamicHashStringBase, s: str)[source]

Bases: object

all_get() int[source]
all_reverse() None[source]
extend(other: DynamicHashString) None[source]
get(l: int, r: int) int[source]
insert(k: int, c: str) None[source]

位置 kc を挿入します。 \(O(\log{n})\) です。

pop(k: int) int[source]
reverse(l: int, r: int) None[source]
set(k: int, c: str) None[source]
split(k: int) tuple[DynamicHashString, DynamicHashString][source]
class DynamicHashStringBase(n: int = 0, base: int = -1, seed: int | None = None)[source]

Bases: object

動的な文字列に対するロリハです。

平衡二分木にモノイドを載せてるだけです。こんなライブラリ必要ないです。

Example

``` base = DynamicHashStringBase(2 * 10**5 + 1) dhs_s = DynamicHashString(base, s) dhs_t = DynamicHashString(base, t)

pref = dhs_s.get(0, r) suff = dhs_t.get(l, n) h = base.unite(pref, suff, n-l) ```

extend(cap: int) None[source]
get_cap() int[source]
static get_mod(x: int) int[source]
static get_mul(a: int, b: int) int[source]
unite(h1: int, h2: int, k: int) int[source]

2つの hash 値を concat します。

Parameters:
  • h1 (int) – prefix

  • h2 (int) – suffix

  • k (int) – h2の長さ

Returns:

h1 + h2

Return type:

int