把$($看作$-1$,$)$看作$1$,设$a$为前缀和,则相当于找两个位置$x,y$使得$a[x]=a[y]$,且$a[x]$是$[x,y]$的区间最大值。

求出询问区间的最大值$o$,然后找到$o$在该区间内最左和最右的出现位置,将其作为答案。

那么剩下的答案只可能在$[l,o)$或$(o,r]$,以$[l,o)$为例。

通过单调栈求出每个位置$i$往右最长延伸长度$g[i]$,使得中间$a[i]$是区间最大值,且$a[i]=a[i+g[i]]$。

那么在$[l,o)$中,因为$o$的阻隔,必然满足$i+g[i]<o$,找到最大的即可。

时间复杂度$O(n\log n)$。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef pair<int,int>P;
const int N=400010,M=1050000,inf=~0U>>1;
int n,m,i,x,y,l,r,o,ans,a[N],q[N],t,f[N],g[N],v[M],vf[M],vg[M];P b[N];char s[N];
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
inline void up(int&a,int b){a<b?(a=b):0;}
void build(int x,int a,int b){
if(a==b){
v[x]=::a[a];
vf[x]=f[a];
vg[x]=g[a];
return;
}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
v[x]=max(v[x<<1],v[x<<1|1]);
vf[x]=max(vf[x<<1],vf[x<<1|1]);
vg[x]=max(vg[x<<1],vg[x<<1|1]);
}
int ask(int x,int a,int b,int c,int d,int*v){
if(c<=a&&b<=d)return v[x];
int mid=(a+b)>>1,t=-inf;
if(c<=mid)t=ask(x<<1,a,mid,c,d,v);
if(d>mid)up(t,ask(x<<1|1,mid+1,b,c,d,v));
return t;
}
int main(){
scanf("%d%d%s",&n,&m,s+2);n++;
for(i=2;i<=n;i++)a[i]=a[i-1]+(s[i]==')'?1:-1);
for(i=1;i<=n;i++)b[i]=P(a[i],i);
sort(b+1,b+n+1);
for(q[t=0]=0,i=1;i<=n;q[++t]=i++){
while(t&&a[i]>=a[q[t]])t--;
f[i]=i-upper_bound(b+1,b+n+1,P(a[i],q[t]))->second;
}
for(q[t=0]=n+1,i=n;i;q[++t]=i--){
while(t&&a[i]>=a[q[t]])t--;
g[i]=(lower_bound(b+1,b+n+1,P(a[i],q[t]))-1)->second-i;
}
build(1,1,n);
while(m--){
read(x),read(y);y++;
o=ask(1,1,n,x,y,v);
l=lower_bound(b+1,b+n+1,P(o,x))->second;
r=(upper_bound(b+1,b+n+1,P(o,y))-1)->second;
ans=r-l;
if(l>x)up(ans,ask(1,1,n,x,l-1,vg));
if(r<y)up(ans,ask(1,1,n,r+1,y,vf));
printf("%d\n",ans);
}
return 0;
}

  

04-26 04:02