from itertools import accumulate
from operator import add
from typing import TypeVar, Generic, Callable, List
T = TypeVar('T')
U = TypeVar('U')
class LazySegmentTreeInjectable(Generic[T, U]):
def __init__(self,
n: int,
identity_data: Callable[[], T],
identity_lazy: Callable[[], U],
operation: Callable[[T, T], T],
mapping: Callable[[T, U], T],
composition: Callable[[U, U], U],
):
self.n = n
self.depth = n.bit_length()
self.offset = 1 << self.depth
self.identity_data = identity_data
self.identity_lazy = identity_lazy
self.operation = operation
self.mapping = mapping
self.composition = composition
self.data = [identity_data() for _ in range(self.offset << 1)]
self.lazy = [identity_lazy() for _ in range(self.offset)]
@classmethod
def from_array(cls,
arr: List[T],
identity_data: Callable[[], T],
identity_lazy: Callable[[], U],
operation: Callable[[T, T], T],
mapping: Callable[[T, U], T],
composition: Callable[[U, U], U],
):
ins = cls(len(arr), identity_data, identity_lazy, operation, mapping, composition)
ins.data[ins.offset:ins.offset + ins.n] = arr
for i in range(ins.offset - 1, 0, -1):
ins.update(i)
return ins
def push(self, i: int) -> None:
if i < self.offset:
data = self.data
lazy = self.lazy
lz = lazy[i]
lch = i << 1
rch = lch + 1
data[lch] = self.mapping(data[lch], lz)
data[rch] = self.mapping(data[rch], lz)
if lch < self.offset:
lazy[lch] = self.composition(lazy[lch], lz)
lazy[rch] = self.composition(lazy[rch], lz)
lazy[i] = self.identity_lazy()
def update(self, i: int) -> None:
lch = i << 1
rch = lch + 1
self.data[i] = self.operation(self.data[lch], self.data[rch])
def all_apply(self, i: int, d: U) -> None:
self.data[i] = self.mapping(self.data[i], d)
if i < self.offset:
self.lazy[i] = self.composition(self.lazy[i], d)
def propagate(self, l: int, r: int) -> None:
for i in range(self.depth, 0, -1):
if ((l >> i) << i) != l:
self.push(l >> i)
if ((r >> i) << i) != r:
self.push((r - 1) >> i)
def range_update(self, l: int, r: int, d: U) -> None:
l += self.offset
r += self.offset
self.propagate(l, r)
l2 = l
r2 = r
while l < r:
if (l & 1) == 1:
self.all_apply(l, d)
l += 1
if (r & 1) == 1:
r -= 1
self.all_apply(r, d)
l >>= 1
r >>= 1
l = l2
r = r2
for i in range(1, self.depth + 1):
if ((l >> i) << i) != l:
self.update(l >> i)
if ((r >> i) << i) != r:
self.update((r - 1) >> i)
def range_query(self, l: int, r: int) -> T:
l += self.offset
r += self.offset
self.propagate(l, r)
sml = self.identity_data()
smr = self.identity_data()
while l < r:
if (l & 1) == 1:
sml = self.operation(sml, self.data[l])
l += 1
if (r & 1) == 1:
r -= 1
smr = self.operation(self.data[r], smr)
l >>= 1
r >>= 1
return self.operation(sml, smr)
def point_set(self, p: int, d: T) -> None:
p += self.offset
for i in range(self.depth, 0, -1):
self.push(p >> i)
self.data[p] = d
for i in range(1, self.depth + 1):
self.update(p >> i)
def point_get(self, p: int) -> T:
p += self.offset
for i in range(self.depth, 0, -1):
self.push(p >> i)
return self.data[p]
def debug_print(self) -> None:
i = 1
while i <= self.offset:
print(*map('{: 4d}'.format, self.data[i:i * 2]))
i <<= 1
i = 1
while i <= self.offset:
print(*map('{: 4d}'.format, self.lazy[i:i * 2]))
i <<= 1
n, q = map(int, input().split())
s = input()
aaa = [1 if c == '(' else -1 for c in s]
acc = [0] + list(accumulate(aaa))
INF = 1 << 60
identity_data = lambda: INF
identity_lazy = int
operation = min
mapping = add
composition = add
lst = LazySegmentTreeInjectable.from_array(acc, identity_data, identity_lazy, operation, mapping, composition)
for _ in range(q):
op, l, r = map(int, input().split())
l -= 1
r -= 1
if op == 1:
if aaa[l] == aaa[r]:
continue
if aaa[l] == 1:
lst.range_update(l + 1, r + 1, -2)
else:
lst.range_update(l + 1, r + 1, 2)
aaa[l], aaa[r] = aaa[r], aaa[l]
else:
lp = lst.point_get(l)
rp = lst.point_get(r + 1)
range_min = lst.range_query(l + 1, r + 1)
if lp == rp and lp <= range_min:
print('Yes')
else:
print('No')