zoukankan      html  css  js  c++  java
  • bzoj4964: 加长的咒语

    无修改询问区间最长子串满足它是一个括号序列,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
    ",as[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    TextView走马灯
    Android apk安装时出现“解析软件包错误”
    Android Studio调试手机或者安装APK的时候出现install failed test only
    如何动态改变报表的行高列宽
    如何动态的给报表添加目录
    免费报表工具零代码零基础轻松搞定 web 报表
    脚本中如何做填报数据校验
    脚本填报表的条件查询
    脚本模式下的填报表制作
    交叉填报表的制作
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7309194.html
Copyright © 2011-2022 走看看