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);
    }
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12326216.html