https://www.nowcoder.com/acm/contest/201/J
题意:
有m种括号,给你一个括号字符串,每次询问问你l到r合法不。
POINT:
注意:([)]这样的括号匹配是不合法的。
这样就很容易知道,每一个右括号如果能匹配,肯定是有唯一的左括号的。
如果只有一种括号,我们怎么判断他合法的呢:
遇左加入栈,遇右pop栈,如果栈空,则不合法。如果最后栈不空,则不合法。把左括号变为1,右括号为-1.
若要合法,也就是l到r的和为0,且在l到r的任意时刻,和都不能为负数,(即右括号比左括号多了)。
那么这题也差不多。遇左加入栈,遇右,看看栈顶的左括号和右括号匹不匹配,匹配,则把左右括号的相对位置上的值变为1和-1.
若不匹配,那么这个右括号已经无效了,而且只要l到r内包含这个右括号,必定使串不合法。
不是1和-1的全变成-inf
这样一个操作之后。我们得到了一个1 -1 -inf的串。
比如(())[(])[] 这个串为1 1 -1 -1 -inf -inf -inf -inf 1 -1。
然后我们查询l到r这个串合不合法,先只要看sum(l,r)==0,若等于0,若为0 ,则再看中途有没有变为负数:
这个怎么看,我们维护一个前缀和pre。 一段区间[L,R]的和是pre[R]-pre[L-1]。
那么我们只要找到[L,R]中最小的pre,如果这个最小的pre-pre[L-1]>=0的话,就证明中途没有变为负数。
这样这个区间就合法了。
找区间内最小值,RMQ或者线段树。这题RMQ比较快,因为没有修改操作。但我用了线段树
#include
#include
#include
#include
using namespace std;
const int N = 1e6 + 1000;
#define LL long long
const LL inf = 0x3f3f3f3f3f3f3f3f;
LL sum[N];
int a[N];
LL Min[N<<2];
int b[N];
struct node
{
int id ,val;
}stk[N];
int top=0;
void build(int x,int l,int r)
{
if(l==r){
Min[x]=sum[l];
return;
}
int mid = (l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
Min[x]=min(Min[x<<1],Min[x<<1|1]);
}
LL query(int x,int l,int r,int ll,int rr)
{
if(ll<=l&&rr>=r){
return Min[x];
}else{
LL ans=inf;
int mid = (l+r)>>1;
if(ll<=mid) ans=min(ans,query(x<<1,l,mid,ll,rr));
if(mid=1){
if(stk[top].val%2==0&&stk[top].val+1==a[i]){
b[stk[top].id]=1;
b[i]=-1;
top--;
}else{
top=0;
}
}
}
}
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+b[i];
build(1,1,n);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
if(sum[r]-sum[l-1]!=0||query(1,1,n,l,r)