#include using namespace std; struct Node { int prev; // previous open frame int state; // 0,1,2,3 }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int Q; cin >> Q; vector st(1, {-1, 0}); // st[0] is dummy null vector topv(1, 0); // top node id for each prefix vector badv(1, 0); // whether current prefix is invalid vector donev(1, 0); // whether we have completed a top-level good string auto push_node = [&](int prev, int state) { st.push_back({prev, state}); return (int)st.size() - 1; }; for (int qi = 0; qi < Q; qi++) { int t; cin >> t; if (t == 1) { char c; cin >> c; int top = topv.back(); bool bad = badv.back(); bool done = donev.back(); int newTop = top; bool newBad = bad; bool newDone = done; if (bad) { // once invalid, appending keeps it invalid newBad = true; } else if (c == '(') { // can only start a new frame if we haven't finished a top-level good string if (top == 0 && done) { newBad = true; } else { newTop = push_node(top, 0); newDone = false; } } else if (c == '|') { if (top == 0) { newBad = true; } else { int s = st[top].state; if (s == 0 || s == 1) { // move to the second part newTop = push_node(st[top].prev, 2); newDone = false; } else { newBad = true; } } } else if (c == ')') { if (top == 0) { newBad = true; } else { int s = st[top].state; int parent = st[top].prev; // close current frame if (parent == 0) { // top-level expression finished newTop = 0; newDone = true; } else { int ps = st[parent].state; if (ps == 0) { newTop = push_node(st[parent].prev, 1); } else if (ps == 2) { newTop = push_node(st[parent].prev, 3); } else { newBad = true; } newDone = false; } } } else { newBad = true; } topv.push_back(newTop); badv.push_back(newBad); donev.push_back(newDone); } else { // delete last character topv.pop_back(); badv.pop_back(); donev.pop_back(); } // good iff not invalid and no open frames cout << ((!badv.back() && topv.back() == 0) ? "Yes" : "No") << '\n'; } return 0; }