Official

C - Brackets Stack Query Editorial by en_translator


This problem asks you to utilize properties of good (balanced) parenthesis sequences.
A good parenthesis sequence has the following property:

Let \(S\) be a string of ( and ).
Define a sequence \(A=(A_0, A_1, \dots, A_{|S|})\) of length \((|S|+1)\) as follows:

  • \(A_0 = 0\)
  • \(A_1 = A_0 + (1 \text{ if } S_1 =\) ( \(\text{ else } -1)\)
  • \(\vdots\)
  • \(A_i = A_{i-1} + (1 \text{ if } S_i =\) ( \(\text{ else } -1)\)
  • \(\vdots\)
  • \(A_{|S|} = A_{|S|-1} + (1 \text{ if } S_{|S|} =\) ( \(\text{ else } -1)\)

Then \(S\) is a good parenthesis sequence if and only if:

  • \(A_{|S|} = 0\) and \(\min\lbrace A_0, A_1, \dots, A_{|S|} \rbrace = 0\).

If you are not convinced, trying calculating \(A\) for several instances of parenthesis sequences \(S\) may help understanding. (We omit the proof here.)

The problem can be solved by managing \(A\) of the property above in a stack-like data structure. Specifically, for the current string \(S\), we define \(B_i = \min \lbrace A_0, A_1, \dots, A_i \rbrace\) and store

  • the values \(A_0, A_1, \dots, A_{|S|}\) of \(A\), and
  • the values \(B_0, B_1, \dots, B_{|S|}\) of \(B\)

in a stack.
Initially, \(S\) is an empty string, so they only contain \(A_0 = 0\) and \(B_0 = 0\).
When appending ( according to type-1 query, we have

  • \(A_n = A_{n - 1} + 1\)
  • \(B_n = \min \lbrace A_0, A_1, \dots, A_n \rbrace = \min \lbrace B_{n-1}, A_n \rbrace\)

where \(n\) is the new length of the string, so \(A_n\) and \(B_n\) can be computed as per to the previous information. Same goes for appending ) too.
When removing the last character of \(S\) by a type-2 query, we can simply remove the last elements of \(A\) and \(B\).
Whether the current string is a good parenthesis sequence can be determined whether \(A_{|S|} = 0\) and \(B_{|S|} = 0\) both hold.

The problem can be solved by constructing a data structure described above. The computational complexity is \(\mathrm{O}(Q)\), which is fast enough.

  • Sample code (C++)
#include <iostream>
#include <vector>
using namespace std;

int main() {
  cin.tie(0)->sync_with_stdio(0);
  int Q;
  cin >> Q;
  vector<int> A{0}, B{0};
  for (int q = 1; q <= Q; q++) {
    int cmd;
    cin >> cmd;
    if (cmd == 1) {
      char c;
      cin >> c;
      A.push_back(A.back() + (c == '(' ? 1 : -1));
      B.push_back(min(B.back(), A.back()));
    } else {
      A.pop_back();
      B.pop_back();
    }
    cout << (A.back() == 0 and B.back() == 0 ? "Yes" : "No") << "\n";
  }
}

posted:
last update: