无修改询问区间最长子串满足它是一个括号序列,N,Q<=400000
考虑分治,处理跨过分治中点的询问
预处理在中点一侧的最优答案,剩下只有最优答案跨过中点的情况,可以两侧贪心取前缀和最小位置,再进行调整,如图
时间复杂度O(nlogn)
#include<bits/stdc++.h> const int N=4e5+7; char buf[N*25],*ptr=buf; int _(){ int x=0; while(*ptr<48)++ptr; while(*ptr>47)x=x*10+*ptr++-48; return x; } int n,m; struct itv{ int l,r,id; }is[N],is2[N]; int as[N],v[N],s[N],mx[N]; int pw[N],nx[N]; bool ed[N]; int ws[N],wp=0,xs[N],xp=0,xr[N],ma[N]; int max(int a,int b){return a>b?a:b;} void maxs(int&a,int b){if(a<b)a=b;} int query(int l,int r,int m){ int lp=mx[l],rp=mx[r],v=0; if(s[lp]<s[rp]){ int L=xr[ws[rp]],R=xr[ws[rp]+1]-1; while(L<R){ int M=L+R>>1; xs[M]<lp?L=M+1:R=M; } v=rp-xs[L]; }else{ int L=xr[ws[lp]],R=xr[ws[lp]+1]-1; while(L<R){ int M=L+R+1>>1; xs[M]>rp?R=M-1:L=M; } v=xs[L]-lp; } return max(v,max(ma[l-1],ma[r])); } void pre(int l,int r,int m){ pw[0]=m+1; ma[m]=0; for(int i=m,mv=0,mw=m,x=0,pp=0;i>=l;--i){ x+=v[i]; if(x>=mv)mv=x,mw=i-1; mx[i]=mw; ma[i-1]=ma[i]; if(v[i]<0)pw[++pp]=i; else if(pp)maxs(ma[i-1],pw[--pp]-i); else pw[0]=i; } pw[0]=m; for(int i=m+1,mv=0,mw=m,x=0,pp=0;i<=r;++i){ x-=v[i]; if(x>=mv)mv=x,mw=i; mx[i]=mw; ma[i]=ma[i-1]; if(v[i]>0)pw[++pp]=i; else if(pp)maxs(ma[i],i-pw[--pp]); else pw[0]=i; } } void calc(int l,int r,int L,int R){ if(l>r||L==R)return; int M=L+R>>1,p1=l,p2=r; pre(L,R,M); for(int i=l;i<=r;++i){ if(is[i].r<=M)is2[p1++]=is[i]; else if(is[i].l>M)is2[p2--]=is[i]; else as[is[i].id]=query(is[i].l,is[i].r,M); } memcpy(is+l,is2+l,(p1-l)*sizeof(itv)); memcpy(is+p2+1,is2+p2+1,(r-p2)*sizeof(itv)); calc(l,p1-1,L,M); calc(p2+1,r,M+1,R); } int main(){ fread(buf,1,sizeof(buf),stdin); n=_(),m=_(); while(*ptr<33)++ptr; for(int i=1,pp=0;i<=n;++i){ if(ptr[i-1]=='('){ v[i]=1; pw[++pp]=i; }else{ v[i]=-1; if(pp){ nx[pw[--pp]]=i; pw[pp]=i; }else pw[0]=i; } s[i]=s[i-1]+v[i]; } for(int i=0;i<=n;++i)if(!ed[i]){ int w=i; xr[wp]=xp; do{ ws[xs[xp++]=w]=wp; ed[w]=1; }while(w=nx[w]); ++wp; } xr[wp]=xp; ptr+=n; for(int i=1;i<=m;++i){ is[i].l=_(); is[i].r=_(); is[i].id=i; } calc(1,m,1,n); for(int i=1;i<=m;++i)printf("%d\n",as[i]); return 0; }