题意大致是给出一个括号序列,然后给出多组询问,每次判断一个区间里的括号是否是匹配的。
具体可见。
这里给出两种做法。
对于一个括号序列,如果我们想让所有的括号尽可能多的匹配,每个单括号应该只对应唯一的另一个单括号与它匹配。那么我们就可以比较加入a[l]之前栈里留下的括号的状态,和加入a[r]以后栈里留下的括号的状态,如果一样,相当于这段区间的括号"消掉了",也就是这段区间是匹配的。
另一种想法:既然我们要判断的是一个区间里的括号是否是匹配,那么我们已经知道括号序列的匹配方式是唯一的,如果我们在区间里任意取出一个单括号,与它匹配的单括号也必须在这个区间里,否则这个区间的括号是不匹配的,这种性质我把它称为"封闭性"。 所以我们先预处理与每一个位置单括号匹配的另一个单括号的编号x[i]。 但是即使我们预处理完了以后,查询一个区间的复杂度仍然是线性的。 但其实我们只需要查询这个区间里x[i]的最大值和最小值即可,最大值是右端点,最小值是左端点说明这个区间是封闭的,即匹配的(这里可能会出现有的单括号根本找不到匹配的单括号的情况,所以预处理的时候请把这些括号的x[i]设置为-1),否则必然不是匹配的。查询最值线段树或RMQ都可。
2种方法的具体代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,m,q;
int a[maxn],x[maxn];
stack<int>s;
int main()
{
scanf("%d %d %d",&n,&m,&q);
while(!s.empty()) s.pop();
for(int i=1;i<=n;i++)
scanf("%d",a+i);
for(int i=1;i<=n;i++)
{
if(s.empty()||!(a[i]&1))
s.push(i);
else if(a[s.top()]+1==a[i])
s.pop();
else s.push(i);
if(s.empty()) x[i]=0;
else x[i]=s.top();
}
while(q--)
{
int l,r;
scanf("%d %d",&l,&r);
if(x[l-1]==x[r])
printf("Yes\n");
else printf("No\n");
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int n,m,q;
int a[maxn],b[maxn],x[maxn<<2],y[maxn<<2];
stack<int>s;
void build(int R,int l,int r)
{
if(l==r)
{
x[R]=b[l];
y[R]=b[l];
return;
}
int mid=l+r>>1;
build(R<<1,l,mid);
build(R<<1|1,mid+1,r);
x[R]=min(x[R<<1],x[R<<1|1]);
y[R]=max(y[R<<1],y[R<<1|1]);
}
void ask(int R,int l,int r,int ql,int qr,int &u,int &v)
{
if(ql<=l&&r<=qr)
{
u=min(u,x[R]);
v=max(v,y[R]);
return ;
}
int mid=l+r>>1;
if(ql<=mid) ask(R<<1,l,mid,ql,qr,u,v);
if(qr>mid) ask(R<<1|1,mid+1,r,ql,qr,u,v);
}
int main()
{
scanf("%d %d %d",&n,&m,&q);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
b[i]=-1;
if(s.empty()||!(a[i]&1)) s.push(i);
else if (a[s.top()]+1==a[i]) b[i]=s.top(),b[s.top()]=i,s.pop();
else s.push(i);
}
build(1,1,n);
while(q--)
{
int ql,qr;
scanf("%d %d",&ql,&qr);
int _1=1e9,_2=-2;
ask(1,1,n,ql,qr,_1,_2);
if(_1==ql&&_2==qr)
puts("Yes");
else puts("No");
}
return 0;
}