Description
给定一个括号序列,每次询问一个区间,求这个区间的所有子序列中,合法括号序列的最大长度。
Solution
考虑线段树,对于一个区间,其内部相互匹配后,一定会剩下若干的左括号堆积在右侧,若干的右括号堆积在左侧。
合并区间时,左边剩余的左括号和右边剩余的右括号会相互消去一部分。
#include <bits/stdc++.h>
using namespace std;
string seq_str;
int seq_len, num_query;
struct SegmentTree
{
struct Node
{
int left_bracket; // 右边堆积的左括号数目
int right_bracket; // 左边堆积的右括号数目
};
friend Node operator+(const Node &lhs, const Node &rhs)
{
return {lhs.left_bracket + rhs.left_bracket - min(lhs.left_bracket, rhs.right_bracket),
lhs.right_bracket + rhs.right_bracket - min(lhs.left_bracket, rhs.right_bracket)};
}
Node *node;
int seg_len;
SegmentTree(int n_)
{
seg_len = n_;
node = new Node[4 * seg_len + 5];
}
void pushup(int p)
{
node[p] = node[p * 2] + node[p * 2 + 1];
}
void build(int p, int l, int r, string &str)
{
if (l == r)
{
node[p] = {str[l - 1] == '(', str[l - 1] == ')'};
}
else
{
build(p * 2, l, (l + r) / 2, str);
build(p * 2 + 1, (l + r) / 2 + 1, r, str);
pushup(p);
}
}
void Build(string &str)
{
build(1, 1, seg_len, str);
}
Node query(int p, int l, int r, int ql, int qr)
{
if (l > qr || r < ql)
return {0, 0};
if (l >= ql && r <= qr)
return node[p];
return query(p * 2, l, (l + r) / 2, ql, qr) + query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr);
}
Node Query(int ql, int qr)
{
return query(1, 1, seg_len, ql, qr);
}
int QueryAns(int ql, int qr)
{
auto tmp = Query(ql, qr);
return (qr - ql + 1 - tmp.left_bracket - tmp.right_bracket);
}
};
int main()
{
ios::sync_with_stdio(false);
cin >> seq_str;
cin >> num_query;
seq_len = seq_str.length();
SegmentTree segment_tree(seq_len);
segment_tree.Build(seq_str);
for (int i = 1; i <= num_query; i++)
{
int l, r;
cin >> l >> r;
cout<<segment_tree.QueryAns(l,r)<<endl;
}
}