Editorial for Sub Sub Strings
Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.
Submitting an official solution before solving the problem yourself is a bannable offence.
Approach
Build a segment tree over the string. Each node stores:
- the leftmost and rightmost characters in its range
- the longest same-character prefix and suffix lengths
- whether the whole range is a single character
- the longest same-character run anywhere in the range
When merging two nodes, the answer is the maximum of:
- the left child's best run
- the right child's best run
- the run formed across the boundary, if the left child's rightmost character equals the right child's leftmost character
Each query then returns the best run in in
time. Building the tree costs
, so the total time complexity is
.
Solution (Python)
from __future__ import annotations
from dataclasses import dataclass
from typing import Callable, Generic, List, TypeVar
import copy
T = TypeVar("T")
class SegmentTree(Generic[T]):
def __init__(self, arr: List[T], combine: Callable[[T, T], T]) -> None:
self.combine = combine
self.length = len(arr)
self.array = [0] * (self.length * 4 + 1)
self.__build(1, 0, self.length - 1, arr)
def __build(self, v: int, tl: int, tr: int, arr: List[T]) -> None:
if tl == tr:
self.array[v] = arr[tl]
else:
tm = (tl + tr) // 2
self.__build(2 * v, tl, tm, arr)
self.__build(2 * v + 1, tm + 1, tr, arr)
self.array[v] = self.combine(self.array[2 * v], self.array[2 * v + 1])
def update(self, index: int, value: T) -> None:
self.__update(index, 1, 0, self.length - 1, value)
def __update(self, index: int, v: int, tl: int, tr: int, value: T) -> None:
if tl == tr:
self.array[v] = value
return
tm = (tl + tr) // 2
if index <= tm:
self.__update(index, 2 * v, tl, tm, value)
else:
self.__update(index, 2 * v + 1, tm + 1, tr, value)
self.array[v] = self.combine(self.array[2 * v], self.array[2 * v + 1])
def query(self, l: int, r: int) -> T:
return copy.copy(self.__query(1, 0, self.length - 1, l, r))
def __query(self, v: int, tl: int, tr: int, l: int, r: int) -> T:
if tl == l and tr == r:
return self.array[v]
tm = (tl + tr) // 2
if r <= tm:
return self.__query(2 * v, tl, tm, l, r)
if l > tm:
return self.__query(2 * v + 1, tm + 1, tr, l, r)
return self.combine(
self.__query(2 * v, tl, tm, l, tm),
self.__query(2 * v + 1, tm + 1, tr, tm + 1, r),
)
@dataclass
class Node:
left_char: str
right_char: str
left_max: int
right_max: int
max: int
one_char: bool
def combine(left: Node, right: Node) -> Node:
res = Node("c", "c", 1, 1, 1, True)
res.left_char = left.left_char
res.right_char = right.right_char
res.one_char = left.right_char == right.left_char and left.one_char and right.one_char
if left.one_char and left.right_char == right.left_char:
res.left_max = left.max + right.left_max
else:
res.left_max = left.left_max
if right.one_char and left.right_char == right.left_char:
res.right_max = right.max + left.right_max
else:
res.right_max = right.right_max
res.max = max(left.max, right.max)
if left.right_char == right.left_char:
res.max = max(res.max, left.right_max + right.left_max)
return res
n, q = (int(x) for x in input().split())
arr = [Node(x, x, 1, 1, 1, True) for x in input()]
tree = SegmentTree[Node](arr, combine)
for _ in range(q):
a, b = (int(x) - 1 for x in input().split())
print(tree.query(a, b).max)
Comments