zoukankan      html  css  js  c++  java
  • Luogu P4094 [HEOI2016/TJOI2016]字符串

    Link
    考虑二分答案(lim)
    那么我们现在要求的是是否存在(iin[a,b],s.t. lcp(suf_i,suf_c)ge lim)
    (rand_c)开始往两端扩展到([l,r]),满足(forall iin(l,r],h_ige mid)
    那么我们要求的就是在(sa_l,cdots,sa_r)中是否存在一个属于([a,b])的数。
    这是一个典型的二位数点问题,可以用主席树解决。
    而要求(l,r)可以预处理RMQ+倍增。
    时间复杂度(O(nlog n+mlog^2n))

    #include<cstdio>
    #include<cctype>
    #include<numeric>
    #include<cstring>
    #include<algorithm>
    const int N=100007;
    char str[N+10];
    int n,q,cnt,sa[N],rank[N],h[N],s[N<<1],t[N<<1],pos[N<<1],r[N>>1],c[N>>1],f[17][N],root[N],ls[N<<5],rs[N<<5],sum[N<<5];
    int read(){int x=0,c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
    #define is(x,a) sa[r[s[x]]a]=x
    #define IS(S)								
        memset(sa+1,0,n<<2),memset(c+1,0,m<<2);				
        for(int i=1;i<=n;++c[s[i++]]);					
        std::partial_sum(c+1,c+m+1,c+1),memcpy(r+1,c+1,m<<2);		
        for(int i=N;i;--i) is(S[i],--);					
        for(int i=1;i<=m;++i) r[i]=c[i-1]+1;				
        for(int i=1;i<=n;++i) if(sa[i]>1&&t[sa[i]-1]) is(sa[i]-1,++);	
        memcpy(r+1,c+1,m<<2);						
        for(int i=n;i;--i) if(sa[i]>1&&!t[sa[i]-1]) is(sa[i]-1,--);
    void SAIS(int n,int m,int*s,int*t,int*pos)
    {
        int N=0,M=rank[1]=0,*S=s+n;
        t[n]=0;
        for(int i=n-1;i;--i) t[i]=s[i]^s[i+1]? s[i]>s[i+1]:t[i+1];
        for(int i=2;i<=n;++i) rank[i]=t[i-1]&&!t[i]? pos[++N]=i,N:0;
        IS(pos);
        for(int i=1,x,y=0;i<=n;++i)
    	if((x=rank[sa[i]]))
    	{
    	    if(M<=1||pos[x+1]-pos[x]!=pos[y+1]-pos[y]) ++M;
    	    else for(int a=pos[x],b=pos[y];a<=pos[x+1];++a,++b) if((s[a]<<1|t[a])^(s[b]<<1|t[b])) {++M;break;}
    	    S[y=x]=M;
    	}
        if(M^N) SAIS(N,M,S,t+n,pos+n); else for(int i=1;i<=N;++i) sa[S[i]]=i;
        for(int i=1;i<=N;++i) S[i]=pos[sa[i]];
        IS(S);
    }
    #define mid ((l+r)>>1)
    void update(int&x,int p,int l,int r,int t)
    {
        sum[x=++cnt]=sum[p]+1,ls[x]=ls[p],rs[x]=rs[p];
        if(l==r) return ;
        t<=mid? update(ls[x],ls[p],l,mid,t):update(rs[x],rs[p],mid+1,r,t);
    }
    int query(int x,int p,int l,int r,int L,int R)
    {
        if(sum[x]==sum[p]||L>r||R<l) return 0;
        if(L<=l&&r<=R) return sum[x]-sum[p];
        return query(ls[x],ls[p],l,mid,L,R)+query(rs[x],rs[p],mid+1,r,L,R);
    }
    #undef mid
    int check(int a,int b,int c,int lim)
    {
        int l=rank[c],r=rank[c];
        for(int i=16,x;~i;--i) if(l>(x=1<<i)&&f[i][l-x+1]>=lim) l-=x;
        for(int i=16,x;~i;--i) if(r+(x=1<<i)<=n&&f[i][r+1]>=lim) r+=x;
        return query(root[l-1],root[r],1,n,a,b-lim+1);
    }
    int main()
    {
        n=read(),q=read(),scanf("%s",str+1);
        for(int i=1;i<=n;++i) s[i]=str[i]-'a'+2;
        s[++n]=1,SAIS(n--,27,s,t,pos);
        for(int i=1;i<=n;++i) rank[sa[i]=sa[i+1]]=i;
        for(int i=1,j,l=0;i<=n;h[rank[i++]]=l) for(j=sa[~-rank[i]],l-=l>0;i+l<=n&&j+l<=n&&s[i+l]==s[j+l];++l);
        memcpy(f[0]+1,h+1,n<<2);
        for(int j=1;j<17;++j) for(int i=1,d=1<<(j-1);i+d<=n;++i) f[j][i]=std::min(f[j-1][i],f[j-1][i+d]);
        for(int i=1;i<=n;++i) update(root[i],root[i-1],1,n,sa[i]);
        for(int a,b,c,d,l,r,ans;q;--q)
        {
    	a=read(),b=read(),c=read(),d=read(),l=ans=0,r=d-c+1;
    	for(int mid;l<=r;) check(a,b,c,mid=(l+r)>>1)? ans=mid,l=mid+1:r=mid-1;
            printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    eBay要怎么转型?
    一张图让你看懂javascript各类型的关系
    闭包概念,匿名函数
    浅析Javascript闭包的特性
    深入理解JavaScript闭包(closure)
    深入理解JavaScript作用域和作用域链
    WPF 学习笔记(一)
    ChromiumWebBrowser flash不能自动播放问题解决方案
    饱含辛酸开发 WPF CustomControl
    KMP算法备忘
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12326216.html
Copyright © 2011-2022 走看看