51Nod1426 沙拉酱括号

134 篇文章 0 订阅
42 篇文章 0 订阅

题目看这里

我们考虑怎样得到最大答案

首先对原序列进行括号配对,没有配对上的那些可以直接扔掉不影响答案

让后我们有一个合法的括号序列

当一对括号与区间有相交但是不包含整个区间时,将会产生一个位置的浪费(在区间内的那个左括号或者右括号没法配对了),所以答案-1

那么一个区间的答案[l,r]应该是r-l+1-与这个区间相交的括号对数+包含这个区间的括号对数(会被减重)

求相交的个数可以前缀和解决,而求一个区间被括号包含的次数可以用RMQ解决,总复杂度O(n lg n)

线性做法:离线计算所有询问,这样就可以O(1)计算一个区间被包含的次数

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1000010
#define mid (l+r>>1)
using namespace std;
char c[N];
int n,m,s[N],w[N],t=0,l[N],r[N],v[N],a[N],b[N<<2];
void build(int l,int r,int x){
    if(l==r){ b[x]=a[l]; return; }
    build(l,mid,x<<1);
    build(mid+1,r,x<<1|1);
    b[x]=min(b[x<<1],b[x<<1|1]);
}
inline int query(int l,int r,int x,int L,int R){
    if(L<=l && r<=R) return b[x];
    int ans=n;
    if(L<=mid) ans=min(ans,query(l,mid,x<<1,L,R));
    if(mid<R) ans=min(ans,query(mid+1,r,x<<1|1,L,R));
    return ans;
}
int main(){
    scanf("%s%d",c+1,&m); n=strlen(c+1);
    for(int i=1;i<=n;++i){
        if(!t && c[i]==')') v[i]=1;
        else if(c[i]=='(') w[++t]=i;
        else {
            s[i]=w[t]; s[w[t]]=i;
            ++l[w[t]+1]; --l[i+1];
            ++r[w[t]]; --r[i];
            ++a[w[t]]; --a[i+1];
            --t;
        }
    }
    for(;t;--t) v[w[t]]=1;
    for(int i=1;i<=n;++i){
        a[i]+=a[i-1];
        r[i]+=r[i-1]; l[i]+=l[i-1];
    }
    for(int i=1;i<=n;++i) a[i]-=!v[i],v[i]+=v[i-1];
    build(1,n,1);
    for(int x,y;m--;){
        scanf("%d%d",&x,&y);
        printf("%d\n",max(0,y-x+1-(v[y]-v[x-1])-r[y]-l[x]+query(1,n,1,x,y)*2));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值