Cats on the Upgrade (easy version) (Codeforces 1625E1)
Tags: Others, divide and conquer

This is the easy version of the problem. The only difference between the easy and the hard versions are removal queries, they are present only in the hard version."Interplanetary Software, Inc." together with "Robots of Cydonia, Ltd." has developed and released robot cats. These electronic pets can meow, catch mice and entertain the owner in various ways.The developers from "Interplanetary Software, Inc." have recently decided to release a software update for these robots. After the update, the cats must solve the problems about bracket sequences. One of the problems is described below.  First, we need to learn a bit of bracket sequence theory. Consider the strings that contain characters "(", ")" and ".". Call a string regular bracket sequence (RBS), if it can be transformed to an empty string by one or more operations of removing either single "." characters, or a continuous substring "()". For instance, the string "(()(.))" is an RBS, as it can be transformed to an empty string with the following sequence of removals: "(()(.))" $$$\rightarrow$$$ "(()())" $$$\rightarrow$$$ "(())" $$$\rightarrow$$$ "()" $$$\rightarrow$$$ "". We got an empty string, so the initial string was an RBS. At the same time, the string ")(" is not an RBS, as it is not possible to apply such removal operations to it.An RBS is simple if this RBS is not empty, doesn't start with ".", and doesn't end with ".".Denote the substring of the string $$$s$$$ as its sequential subsegment. In particular, $$$s[l\dots r] = s_ls_{l+1}\dots s_r$$$, where $$$s_i$$$ is the $$$i$$$-th character of the string $$$s$$$.Now, move on to the problem statement itself. You are given a string $$$s$$$, initially consisting of characters "(" and ")". You need to answer the queries of the following kind.Given two indices, $$$l$$$ and $$$r$$$ ($$$1 \le l < r \le n$$$), and it's guaranteed that the substring $$$s[l\dots r]$$$ is a simple RBS. You need to find the number of substrings in $$$s[l\dots r]$$$ such that they are simple RBS. In other words, find the number of index pairs $$$i$$$, $$$j$$$ such that $$$l \le i < j \le r$$$ and $$$s[i\dots j]$$$ is a simple RBS.You are an employee in "Interplanetary Software, Inc." and you were given the task to teach the cats to solve the problem above, after the update.Note that the "." character cannot appear in the string in this version of the problem. It is only needed for the hard version.

Input: The first line contains two integers $$$n$$$ and $$$q$$$ ($$$2 \le n \le 3\cdot10^5$$$, $$$1 \le q \le 3\cdot10^5$$$), the length of the string, and the number of queries.The second line contains the string $$$s$$$, consisting of $$$n$$$ characters "(" and ")".Each of the following $$$q$$$ lines contains three integers $$$t$$$, $$$l$$$ and $$$r$$$ ($$$t = 2$$$, $$$1 \le l < r \le n$$$), the queries you need to answer. It is guaranteed that all the queries are valid and correspond to the problem statements. Note that $$$t$$$ is unused and always equal to two in this problem. It is required for the hard version of the problem.

Output: For each query, print a single integer in a separate line, the number of substrings that are simple RBS. The answers must be printed in the same order as the queries are specified in the input.

Note: Consider the example test case.The answer to the first query is $$$3$$$, as there are three suitable substrings: $$$s[3\dots6]$$$, $$$s[3\dots4]$$$ and $$$s[5\dots6]$$$.The answer to the second query is $$$4$$$. The substrings are $$$s[3\dots6]$$$, $$$s[3\dots4]$$$, $$$s[5\dots6]$$$ and $$$s[2\dots7]$$$.The answer to the third query is $$$1$$$. The substring is $$$s[8\dots9]$$$.The answer to the fourth query is $$$6$$$. The substrings are $$$s[3\dots6]$$$, $$$s[3\dots4]$$$, $$$s[5\dots6]$$$, $$$s[2\dots7]$$$, $$$s[8\dots9]$$$ and $$$s[2\dots9]$$$.

Sample Inputs:
9 4
)(()())()
2 3 6
2 2 7
2 8 9
2 2 9

Sample Outputs:
3
4
1
6

Solution (Python):
import sys
I = lambda : [*map(int, sys.stdin.readline().split())]
(n, q) = I()
s = input()
partial = [0]
vals = {0: [0]}
for i in range(n):
    if s[i] == '(':
        new = partial[-1] + 1
    else:
        new = partial[-1] - 1
    if new in vals:
        vals[new].append(i + 1)
    else:
        vals[new] = [i + 1]
    partial.append(new)
inds = [0] * (n + 1)
for guy in vals:
    l = vals[guy]
    for i in range(len(l)):
        inds[l[i]] = i
ans = {}
for i in range(n, -n - 1, -1):
    if i in vals:
        l = vals[i]
        new = [0]
        for j in range(len(l) - 1):
            x = l[j]
            y = l[j + 1]
            if partial[x + 1] > i:
                l1 = ans[i + 1]
                ix = inds[x + 1]
                iy = inds[y - 1]
                tot = l1[iy] - l1[ix]
                diff = iy - ix
                tot += diff * (diff - 1) // 2
                new.append(new[-1] + tot + 1)
            else:
                new.append(new[-1])
        ans[i] = new
for i in range(q):
    (t, l, r) = I()
    l -= 1
    val = partial[l]
    a = ans[val]
    ir = inds[r]
    il = inds[l]
    diff = ir - il
    print(a[ir] - a[il] + diff * (diff - 1) // 2)

Solution (Python):
""""""
import io, os, sys
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
output = sys.stdout.write
DEBUG = os.environ.get('debug') not in [None, '0']
if DEBUG:
    from inspect import currentframe, getframeinfo
    from re import search

def debug(*args):
    if not DEBUG:
        return
    frame = currentframe().f_back
    s = getframeinfo(frame).code_context[0]
    r = search('\\((.*)\\)', s).group(1)
    vnames = r.split(', ')
    var_and_vals = [f'{var}={val}' for (var, val) in zip(vnames, args)]
    prefix = f'{currentframe().f_back.f_lineno:02d}: '
    print(f"{prefix}{', '.join(var_and_vals)}")
INF = float('inf')

class SegmentTreeData:

    def __init__(self, parent=INF, sum=0, cnt=0):
        self.parent = parent
        self.sum = sum
        self.cnt = cnt

    def __add__(self, other):
        res = SegmentTreeData()
        res.sum = self.sum + other.sum
        if self.parent < other.parent:
            (res.parent, res.cnt) = (self.parent, self.cnt)
        elif self.parent > other.parent:
            (res.parent, res.cnt) = (other.parent, other.cnt)
        else:
            (res.parent, res.cnt) = (self.parent, self.cnt + other.cnt)
        return res

    def __repr__(self):
        return f'SegmentTreeData(parent={self.parent},sum={self.sum},cnt={self.cnt})'

class SegmentTree:

    def __init__(self, lo: int, hi: int) -> None:
        """"""
        (self.lo, self.hi) = (lo, hi)
        self.mi = mi = (lo + hi) // 2
        self.data = SegmentTreeData()
        if lo < hi:
            self.left = SegmentTree(lo, mi)
            self.right = SegmentTree(mi + 1, hi)

    def query(self, qlo: int, qhi: int) -> SegmentTreeData:
        """"""
        if qlo < self.lo or qhi > self.hi:
            return SegmentTreeData()
        if qlo == self.lo and qhi == self.hi:
            return self.data
        res = SegmentTreeData()
        if qlo <= self.mi:
            res += self.left.query(qlo, min(qhi, self.mi))
        if qhi > self.mi:
            res += self.right.query(max(qlo, self.mi + 1), qhi)
        return res

    def update(self, qi: int, data: SegmentTreeData):
        """"""
        if qi < self.lo or qi > self.hi:
            return
        if qi == self.lo == self.hi:
            self.data = data
        else:
            if qi <= self.mi:
                self.left.update(qi, data)
            else:
                self.right.update(qi, data)
            self.data = SegmentTreeData()
            if self.left:
                self.data += self.left.data
            if self.right:
                self.data += self.right.data

def solve():
    (N, Q) = map(int, input().split())
    S = input().decode().strip()
    par = [-1] * N
    match = [-1] * N
    stack = []
    for (i, c) in enumerate(S):
        if c == '(':
            stack.append(i)
        elif stack:
            j = stack.pop()
            (match[i], match[j]) = (j, i)
            if j > 0:
                if S[j - 1] == '(':
                    par[j] = j - 1
                elif match[j - 1] != -1:
                    par[j] = par[match[j - 1]]
    deg = [0] * N
    for i in range(N):
        if par[i] != -1:
            deg[par[i]] += 1
    segtree = SegmentTree(0, N - 1)
    for i in range(N):
        if i < match[i]:
            segtree.update(i, SegmentTreeData(par[i], deg[i] * (deg[i] + 1) // 2, 1))
    res = []
    for _ in range(Q):
        (_, l, r) = map(int, input().split())
        v = segtree.query(l - 1, r - 1)
        res.append(v.sum + v.cnt * (v.cnt + 1) // 2)
    print('\n'.join(map(str, res)))
if __name__ == '__main__':
    solve()

Solution (Python):
""""""
import io, os, sys
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline
output = sys.stdout.write
DEBUG = os.environ.get('debug') not in [None, '0']
if DEBUG:
    from inspect import currentframe, getframeinfo
    from re import search

def debug(*args):
    if not DEBUG:
        return
    frame = currentframe().f_back
    s = getframeinfo(frame).code_context[0]
    r = search('\\((.*)\\)', s).group(1)
    vnames = r.split(', ')
    var_and_vals = [f'{var}={val}' for (var, val) in zip(vnames, args)]
    prefix = f'{currentframe().f_back.f_lineno:02d}: '
    print(f"{prefix}{', '.join(var_and_vals)}")
INF = float('inf')

class SegmentTreeData:

    def __init__(self, parent=INF, sum=0, cnt=0):
        self.parent = parent
        self.sum = sum
        self.cnt = cnt

    def __add__(self, other):
        res = SegmentTreeData()
        res.sum = self.sum + other.sum
        if self.parent < other.parent:
            (res.parent, res.cnt) = (self.parent, self.cnt)
        elif self.parent > other.parent:
            (res.parent, res.cnt) = (other.parent, other.cnt)
        else:
            (res.parent, res.cnt) = (self.parent, self.cnt + other.cnt)
        return res

    def __repr__(self):
        return f'SegmentTreeData(parent={self.parent},sum={self.sum},cnt={self.cnt})'

class SegmentTree:

    def __init__(self, lo: int, hi: int) -> None:
        """"""
        (self.lo, self.hi) = (lo, hi)
        self.mi = mi = (lo + hi) // 2
        self.data = SegmentTreeData()
        if lo < hi:
            self.left = SegmentTree(lo, mi)
            self.right = SegmentTree(mi + 1, hi)

    def query(self, qlo: int, qhi: int) -> SegmentTreeData:
        """"""
        if qlo < self.lo or qhi > self.hi:
            return SegmentTreeData()
        if qlo == self.lo and qhi == self.hi:
            return self.data
        res = SegmentTreeData()
        if qlo <= self.mi:
            res += self.left.query(qlo, min(qhi, self.mi))
        if qhi > self.mi:
            res += self.right.query(max(qlo, self.mi + 1), qhi)
        return res

    def update(self, qi: int, data: SegmentTreeData):
        """"""
        if qi < self.lo or qi > self.hi:
            return
        if qi == self.lo == self.hi:
            self.data = data
        else:
            left = self.left.data if self.left else SegmentTreeData()
            right = self.right.data if self.right else SegmentTreeData()
            if qi <= self.mi:
                self.left.update(qi, data)
                left = self.left.data
            else:
                self.right.update(qi, data)
                right = self.right.data
            self.data = left + right

def solve():
    (N, Q) = map(int, input().split())
    S = input().decode().strip()
    par = [-1] * N
    match = [-1] * N
    stack = []
    for (i, c) in enumerate(S):
        if c == '(':
            stack.append(i)
        elif stack:
            j = stack.pop()
            (match[i], match[j]) = (j, i)
            if j > 0:
                if S[j - 1] == '(':
                    par[j] = j - 1
                elif match[j - 1] != -1:
                    par[j] = par[match[j - 1]]
    deg = [0] * N
    for i in range(N):
        if par[i] != -1:
            deg[par[i]] += 1
    segtree = SegmentTree(0, N - 1)
    for i in range(N):
        if i < match[i]:
            segtree.update(i, SegmentTreeData(par[i], deg[i] * (deg[i] + 1) // 2, 1))
    res = []
    for _ in range(Q):
        (_, l, r) = map(int, input().split())
        v = segtree.query(l - 1, r - 1)
        res.append(v.sum + v.cnt * (v.cnt + 1) // 2)
    print('\n'.join(map(str, res)))
if __name__ == '__main__':
    solve()