ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

无修改询问区间最长子串满足它是一个括号序列,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;
}
View Code

 

posted on 2017-08-08 21:44  nul  阅读(267)  评论(0编辑  收藏  举报