:heavy_check_mark: 括弧列区間クエリ (DataStructure/bracket_range_query.hpp)

括弧列区間クエリ

文字列に対して1点更新と区間が正しい括弧列として成立するかの判定を行うデータ構造です。
判定では '('')' 以外の文字は無視します。

  • set(i, c) : i 文字目を c に変更
  • is_valid(l, r) : 区間 [l, r) の部分文字列から '('')' だけを抜き出した列が、正しい括弧列か判定

コンストラクタ

BracketRangeQuery(const std::string& s)

初期文字列 s で初期化します。

制約

  • s は任意の文字列でよい(ただし判定に寄与するのは '('')' のみ)

計算量

  • $O(|s|)$

BracketRangeQuery(int N)

長さ N の文字列で初期化します。初期状態はすべて「括弧以外」(寄与 0)として扱います。

制約

  • $0 \leq N$

計算量

  • $O(N)$

set

void set(int i, char c)

i 文字目(0-indexed)を c に変更します。
c'(' / ')' 以外の場合は、判定上は「無視される文字」として扱われます。

制約

  • 0 ≤ i < N
  • c は任意の文字でよい(ただし判定に寄与するのは '('')' のみ)

計算量

  • $O(\log N)$

is_valid

bool is_valid(int l, int r)

区間 [l, r)(0-indexed)の部分文字列から '('')' のみを抜き出した列が、正しい括弧列であるか判定します。
空区間(l == r)は常に true を返します。

戻り値

  • 正しい括弧列なら true
  • そうでなければ false

制約

  • 0 ≤ l ≤ r ≤ N

計算量

  • $O(\log N)$

str(デバッグ用)

const std::string& str() const

内部に保持している現在の文字列を参照で返します(デバッグ用途を想定)。

計算量

  • $O(1)$

関連情報

Verified with

Code

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

class BracketRangeQuery
{
    using S = int;
    using F = int;

    static constexpr int INF = (int)1e9;

    static S op(S a, S b) { return min(a, b); }
    static S e() { return INF; }

    static S mapping(F f, S x)
    {
        return x == INF ? INF : x + f;
    }

    static F composition(F f, F g)
    {
        return f + g;
    }

    static F id() { return 0; }

    using seg_t = atcoder::lazy_segtree<S, op, e, F, mapping, composition, id>;

public:
    BracketRangeQuery() : n(0), seg() {}

    explicit BracketRangeQuery(const string &s_)
    {
        init(s_);
    }

    explicit BracketRangeQuery(int n_)
    {
        init(string(n_, '?'));
    }

    // i 文字目を c に変更
    void set(int i, char c)
    {
        assert(0 <= i && i < n);
        seg.apply(i + 1, n + 1, conv(c) - conv(s[i]));
        s[i] = c;
    }

    // [l, r) が正しい括弧列か?
    bool is_valid(int l, int r)
    {
        assert(0 <= l && l <= r && r <= n);

        int base = seg.get(l);
        int right = seg.get(r);

        if (right - base != 0)
            return false;
        if (l == r)
            return true;

        int mn = seg.prod(l + 1, r + 1);
        return mn >= base;
    }

    const string &str() const { return s; }

private:
    int n;
    string s;
    seg_t seg;

    static int conv(char c)
    {
        if (c == '(')
            return +1;
        if (c == ')')
            return -1;
        return 0; // 括弧以外は寄与なし
    }

    void init(const string &s_)
    {
        s = s_;
        n = (int)s.size();
        vector<S> pref(n + 1);
        pref[0] = 0;
        for (int i = 0; i < n; ++i)
        {
            pref[i + 1] = pref[i] + conv(s[i]);
        }
        seg = seg_t(pref);
    }
};
#line 1 "DataStructure/bracket_range_query.hpp"
#include <bits/stdc++.h>
#include <atcoder/lazysegtree>
using namespace std;

class BracketRangeQuery
{
    using S = int;
    using F = int;

    static constexpr int INF = (int)1e9;

    static S op(S a, S b) { return min(a, b); }
    static S e() { return INF; }

    static S mapping(F f, S x)
    {
        return x == INF ? INF : x + f;
    }

    static F composition(F f, F g)
    {
        return f + g;
    }

    static F id() { return 0; }

    using seg_t = atcoder::lazy_segtree<S, op, e, F, mapping, composition, id>;

public:
    BracketRangeQuery() : n(0), seg() {}

    explicit BracketRangeQuery(const string &s_)
    {
        init(s_);
    }

    explicit BracketRangeQuery(int n_)
    {
        init(string(n_, '?'));
    }

    // i 文字目を c に変更
    void set(int i, char c)
    {
        assert(0 <= i && i < n);
        seg.apply(i + 1, n + 1, conv(c) - conv(s[i]));
        s[i] = c;
    }

    // [l, r) が正しい括弧列か?
    bool is_valid(int l, int r)
    {
        assert(0 <= l && l <= r && r <= n);

        int base = seg.get(l);
        int right = seg.get(r);

        if (right - base != 0)
            return false;
        if (l == r)
            return true;

        int mn = seg.prod(l + 1, r + 1);
        return mn >= base;
    }

    const string &str() const { return s; }

private:
    int n;
    string s;
    seg_t seg;

    static int conv(char c)
    {
        if (c == '(')
            return +1;
        if (c == ')')
            return -1;
        return 0; // 括弧以外は寄与なし
    }

    void init(const string &s_)
    {
        s = s_;
        n = (int)s.size();
        vector<S> pref(n + 1);
        pref[0] = 0;
        for (int i = 0; i < n; ++i)
        {
            pref[i + 1] = pref[i] + conv(s[i]);
        }
        seg = seg_t(pref);
    }
};
Back to top page