这是2018年牛客网国庆集训的题目,不会也没补,后来准备参加 秦皇岛 CCPC - Winter Camp 时在第一场热身赛时又遇到了。当时热身赛都过了一半了才想起这个事,在图书馆把签到题写了,刚看到这道题就被室友叫去打篮球了。虽然一直牵挂到这道题,直到今天才补上。。。
算是一道比较经典的括号序列题了吧。
题意:
要快速判断一个文档有没有语法错误。
有一个含有
n
n
n 个括号的文档。括号一共有
m
m
m 种,每种括号都有左括号和右括号两种形式,其中偶数为左括号,奇数为右括号,且
⌊
x
2
⌋
\lfloor \frac{x}{2} \rfloor
⌊2x⌋ 相等时为同一种括号。如
0
2
3
1
0\space 2 \space3 \space1
0 2 3 1 为合法的括号序列,而
1
0
2
3
1 \space0 \space2 \space3
1 0 2 3 为非法的括号序列。
我们定义用如下的方式定义一个合法的文档:
1.一个空的字符串是一个合法的文档。
2.如果
A
,
B
A,B
A,B 都是合法的文档,那么
A
B
AB
AB 也是合法的文档。
3.如果
S
S
S 是合法的文档,那么
a
S
b
aSb
aSb 也是合法的文档,其中
a
,
b
a,b
a,b 是同一种括号,并且
a
a
a 是左括号,
b
b
b 是右括号。
现在给出
q
q
q 个询问,每次询问只考虑文档第
l
l
l 至
r
r
r 个字符的情况下,文档是不是合法的。
思路:
- 首先我们会发现,如果在某个区间里面括号 a a a 是与括号 b b b 配对的,那么无论怎么选区间,括号 a a a 始终要与括号 b b b 配对。
- 预处理:先用正常括号匹配的思路,入栈出栈进行匹配整个括号串。用一个数组 b 记录 与其匹配的括号的位置。如 b[i]=x 表示第i个位置与第x位置是配对的。
- 然后就转化成了 RMQ 的问题了。用线段树维护b数组区间最大最小值,如果最大值或最小值在 [ l , r ] [l,r] [l,r] 之外,那这个括号序列就不合法,反之则合法。
坑点:
无
good luck and have fun!!!
附上代码:
#include<bits/stdc++.h>
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define test(flag,value) cout<<flag<<":"<<(value)<<endl
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DB;
const int INF=0x3f3f3f3f;
const int MAXN=1e6;
const double PI=acos(-1);
const int MOD=1e9+7;
int minn[MAXN<<2],maxx[MAXN<<2],a[MAXN],b[MAXN];
void push_up(int rt)
{
minn[rt]=min(minn[rt<<1],minn[rt<<1|1]);
maxx[rt]=max(maxx[rt<<1],maxx[rt<<1|1]);
}
void build(int rt,int l,int r)
{
if(l==r)
{
minn[rt]=b[l];
maxx[rt]=b[l];
return;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
push_up(rt);
}
int query1(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return minn[rt];
int m=(l+r)>>1;
int x1=INF,x2=INF;
if(m>=L) x1=query1(L,R,l,m,rt<<1);
if(m<R) x2=query1(L,R,m+1,r,rt<<1|1);
return min(x1,x2);
}
int query2(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return maxx[rt];
int m=(l+r)>>1;
int x1=0,x2=0;
if(m>=L) x1=query2(L,R,l,m,rt<<1);
if(m<R) x2=query2(L,R,m+1,r,rt<<1|1);
return max(x1,x2);
}
stack<int> S;
stack<int> S2;
int main(void)
{
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
scanf("%d",a+i);
while(!S.empty())S.pop();
while(!S2.empty())S2.pop();
for(int i=1;i<=n;i++)
{
if(S.empty())
{
S.push(a[i]);
S2.push(i);
}
else if(S.top()==a[i]-1&&a[i]%2==1)
{
int x=S2.top();
b[x]=i;
b[i]=x;
S.pop();S2.pop();
}
else
{
S.push(a[i]);
S2.push(i);
}
}
while(!S2.empty())
{
int x=S2.top();
b[x]=-1;
S2.pop();
}
build(1,1,n);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
int y1=query1(l,r,1,n,1);
int y2=query2(l,r,1,n,1);
if(y1<l||y2>r)
printf("No\n");
else
printf("Yes\n");
}
}