F - Parenthesis Checking Editorial by en_translator


First we consider how to determine if a string \(S\) of length \(M\) is a correct parenthesis sequence. Let \(A=(A_1,A_2,\ldots,A_M)\) be the sequence of integers obtained by replacing ( in \(S\) with \(+1\) and ) with \(-1\)m and \(B=(B_0,B_1,\ldots,B_M)\) be the cumulative sums of the prefixes. For example, if \(S=\)(()), then \(A=(1,1,-1,-1)\) and \(B=(0,1,2,1,0)\). Then, \(S\) is a correct parenthesis sequence if and only if:

\(B_M=0\) and the minimum element of \(B\) is \(0\).

The queries in the original problem are queries for segments, so we consider using a segment tree. Each node of the segment tree will manage the minimum element of \(B\) and \(B_M\) for the corresponding to contiguous substring. From these information, two segments can be merged in an \(O(1)\) time, so the problem can be solved using a segment tree capable of one-element updates and contiguous-elements derivations.

Alternatively, we can manage \(B\) it self with a segment tree, using a segment tree capable of contiguous-elements addition and contiguous-elements minimum value derivations.

Sample code (C++)

#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using namespace atcoder;

pair<int, int> op(pair<int, int> a,pair<int, int> b){
    return make_pair(min(a.first, a.second + b.first), a.second + b.second);
}
pair<int, int> e(){
    return make_pair(0, 0);
}

int main(){
    int n, q; cin >> n >> q;
    string s; cin >> s;
    vector<pair<int, int>> v(n);
    for(int i = 0; i < n; i++){
        if(s[i] == '(') v[i] = make_pair(0, 1);
        else v[i] = make_pair(-1, -1);
    }
    segtree<pair<int, int>, op, e> seg(v);
    for(int i = 0; i < q; i++){
        int t, l, r; cin >> t >> l >> r; l--; r--;
        if(t == 1){
            swap(v[l], v[r]);
            seg.set(l, v[l]);
            seg.set(r, v[r]);
        }
        else{
            if(seg.prod(l, r + 1) == make_pair(0, 0)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
    }
}

Sample code (C++) (Alternative solution)

#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using namespace atcoder;

int op(int a, int b){ return min(a, b); }
int e(){ return 1001001001; }
int mapping(int f, int x){ return f+x; }
int composition(int f, int g){ return f+g; }
int id(){ return 0; }

int main(){
    int n, q; cin >> n >> q;
    string s; cin >> s;
    vector<int> v(n + 1);
    for(int i = 0; i < n; i++){
        if(s[i] == '(') v[i + 1] = v[i] + 1;
        else v[i + 1] = v[i] - 1;
    }
    lazy_segtree<int, op, e, int, mapping, composition, id> seg(v);
    for(int i = 0; i < q; i++){
        int t, l, r; cin >> t >> l >> r;
        if(t == 1){
            if(s[l - 1] == '(' && s[r - 1] == ')') seg.apply(l, r, -2);
            if(s[l - 1] == ')' && s[r - 1] == '(') seg.apply(l, r, 2);
            swap(s[l - 1], s[r - 1]);
        }
        else{
            if(seg.prod(l - 1, r + 1) == seg.get(l - 1) && seg.get(l - 1) == seg.get(r)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
    }
}

posted:
last update: