Princess principal - 牛客
题意
有一个\(n\)个括号的文档,括号由\(m\)种。我们定义用如下的方式定义一个合法的文档
-
一个空字符串是一个合法的文档
-
如果\(A\),\(B\)都是合法的文档,那么\(AB\)也是合法的文档
-
如果\(S\)是合法的文档,那么\(aSb\)也是合法的文档,其中\(a,b\)是同一种括号
现给出\(q\)个询问,问\([l,r]\)范围内是否是合法文档。
\(1 \le n, m, q \le 10^6\)
方法一
直接差分,orzzzzz。和只有一种括号的差分是一样一样的。遍历到左括号加一,遍历到匹配的右括号减一,用栈来实现保证了这样做的正确性。。。。
代码
const int N = 1000005;
int n, m, q;
int a[N], ans[N];
stack<int> st;
int main()
{
sc(n), sc(m), sc(q);
Rep(i, 1, n) sc(a[i]);
ans[0] = 0;
Rep(i, 1, n) {
if (st.empty() || (a[i] & 1) == 0) st.push(i);
else {
if (a[st.top()] == a[i] - 1) st.pop();
else st.push(i);
}
if (st.empty()) ans[i] = 0;
else ans[i] = st.top();
}
Rep(i, 1, q) {
int l, r;
sc(l), sc(r);
puts((ans[l - 1] == ans[r] ? "Yes" : "No"));
}
return 0;
}
方法二
先找出不能匹配的位置,① \([l,r]\)包含这些位置就直接判断;② \([l,r]\)是合法位置的子串:对于一个括号,它如果能合法匹配,就记录它匹配的括号的位置。然后查询\([l,r]\)范围内括号的匹配位置pos是否存在\(pos < l\)或者\(pos > r\)。
代码
const int N = 1000005;
int n, m, q, tot;
int use[N], sum[N], le[N], re[N], Min[4 * N], Max[4 * N];
P p[N];
void Pushup(int root) {
Min[root] = min(Min[lson], Min[rson]);
Max[root] = max(Max[lson], Max[rson]);
}
void Build(int l, int r, int root) {
if (l == r) {
tot++;
Min[root] = le[tot];
Max[root] = re[tot];
return;
}
int mid = (l + r) >> 1;
Build(l, mid, lson);
Build(mid + 1, r, rson);
Pushup(root);
}
int QueryMin(int l, int r, int root, int L, int R) {
if (l > R || r < L) return INF32;
if (L <= l && r <= R) return Min[root];
int mid = (l + r) >> 1;
int ans = INF32;
ans = min(ans, QueryMin(l, mid, lson, L, R));
ans = min(ans, QueryMin(mid + 1, r, rson, L, R));
return ans;
}
int QueryMax(int l, int r, int root, int L, int R) {
if (l > R || r < L) return 0;
if (L <= l && r <= R) return Max[root];
int mid = (l + r) >> 1;
int ans = 0;
ans = max(ans, QueryMax(l, mid, lson, L, R));
ans = max(ans, QueryMax(mid + 1, r, rson, L, R));
return ans;
}
int main()
{
sc(n), sc(m), sc(q);
Rep(i, 1, n) {
le[i] = INF32;
re[i] = 0;
sc(p[i].first);
p[i].first = ((p[i].first & 1) ? p[i].first / 2 + m : p[i].first / 2);
p[i].second = i;
}
stack<P> st;
Rep(i, 1, n) {
if (st.empty()) st.push(p[i]);
else {
if (p[i].first >= m) {
P tp = st.top();
st.pop();
if (tp.first != p[i].first - m) {
st.push(p[i]);
st.push(tp);
}
else {
re[tp.second] = p[i].second;
le[p[i].second] = tp.second;
}
}
else {
st.push(p[i]);
}
}
}
while(!st.empty()) {
P tp = st.top();
st.pop();
use[tp.second] = 1;
}
Rep(i, 1, n) sum[i] = sum[i - 1] + use[i];
Build(1, n, 1);
while(q--) {
int l, r;
sc(l), sc(r);
if (use[l] || (sum[l] != sum[r]) || QueryMax(1, n, 1, l, r) > r || QueryMin(1, n, 1, l, r) < l) puts("No");
else puts("Yes");
}
return 0;
}