bzoj4556: [Tjoi2016&Heoi2016]字符串
虽然有准备但是调得就像失了智一样
首先我们先跑一次后缀数组
对于答案二分,找出C的Rank,左右延伸,看最远可以满足的L、R,这个可以通过st表实现
那么对于A~B的字串,它所要满足的,就是A<=i<=B,L<=Rank[i]<=R
那么就按照Rank建主席树,把i插入,查找就找区间L~R内有没有A~B的值
PS:st表那里用倍增应该比较快,但是我没有调出来,那么我就大力二分左右边界,用RMQ求区间最值
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; int n; char ss[110000]; int sa1[110000],Rank[110000]; int sa2[110000],tt[110000],Rsort[110000]; void get_sa(int m) { for(int i=1;i<=n;i++)Rank[i]=ss[i]-'a'+1; memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=n;i++)Rsort[Rank[i]]++; for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1]; for(int i=n;i>=1;i--)sa1[Rsort[Rank[i]]--]=i; int ln=1,p=0; while(p<n) { int k=0;for(int i=n-ln+1;i<=n;i++)sa2[++k]=i; for(int i=1;i<=n;i++) if(sa1[i]-ln>0)sa2[++k]=sa1[i]-ln; memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=n;i++)Rsort[Rank[sa2[i]]]++; for(int i=1;i<=m;i++)Rsort[i]+=Rsort[i-1]; for(int i=n;i>=1;i--)sa1[Rsort[Rank[sa2[i]]]--]=sa2[i]; for(int i=1;i<=n;i++)tt[i]=Rank[i]; p=1;Rank[sa1[1]]=p; for(int i=2;i<=n;i++) { if(tt[sa1[i]]!=tt[sa1[i-1]]||tt[sa1[i]+ln]!=tt[sa1[i-1]+ln])p++; Rank[sa1[i]]=p; } ln*=2;m=p; } } int height[110000]; void get_he() { int j,h=0; for(int i=1;i<=n;i++) { j=sa1[Rank[i]-1]; if(h!=0)h--; while(ss[i+h]==ss[j+h])h++; height[Rank[i]]=h; } } //----------------SA---------------------------- int Bin[30],Log[110000],f[25][110000]; void get_st() { Bin[0]=1;for(int i=1;i<=25;i++)Bin[i]=Bin[i-1]*2; Log[1]=0;for(int i=2;i<=n ;i++)Log[i]=Log[i/2]+1; for(int i=1;i<=n;i++)f[0][i]=height[i]; for(int j=1;Bin[j]<=n;j++) for(int i=1;i+Bin[j]-1<=n;i++) f[j][i]=min(f[j-1][i],f[j-1][i+Bin[j-1]]); } int RMQ(int x,int y) { if(x>y)swap(x,y); int k=Log[y-x+1]; return min(f[k][x],f[k][y-Bin[k]+1]); } int L,R; void getLR(int u,int d) { int l,r;L=u,R=u; l=2,r=u; while(l<=r) { int mid=(l+r)/2; if(RMQ(mid,u)>=d) { L=mid-1; r=mid-1; } else l=mid+1; } l=u+1,r=n; while(l<=r) { int mid=(l+r)/2; if(RMQ(mid,u+1)>=d) { R=mid; l=mid+1; } else r=mid-1; } } //---------------get_st---------------------- struct chairman_tree { int lc,rc,c; }tr[5100000];int trlen,rt[110000]; int maketree(int now,int l,int r,int p) { if(now==0) { now=++trlen; tr[now].lc=tr[now].rc=0; tr[now].c=0; } tr[now].c++; if(l==r)return now; else { int mid=(l+r)/2; if(p<=mid)tr[now].lc=maketree(tr[now].lc,l,mid,p); else tr[now].rc=maketree(tr[now].rc,mid+1,r,p); return now; } } int merge(int x,int y) { if(x==0||y==0)return x+y; tr[x].c+=tr[y].c; tr[x].lc=merge(tr[x].lc,tr[y].lc); tr[x].rc=merge(tr[x].rc,tr[y].rc); return x; } //init~~~ bool check(int x,int y,int l,int r,int ll,int rr) { if(tr[y].c-tr[x].c==0)return false; if(l==ll&&r==rr)return true; int mid=(l+r)/2; if(rr<=mid) return check(tr[x].lc,tr[y].lc,l,mid,ll,rr); else if(mid+1<=ll)return check(tr[x].rc,tr[y].rc,mid+1,r,ll,rr); else return (check(tr[x].lc,tr[y].lc,l,mid,ll,mid)|check(tr[x].rc,tr[y].rc,mid+1,r,mid+1,rr)); } //--------------chairman_tree------------------------ int main() { freopen("str.in","r",stdin); freopen("str.out","w",stdout); int Q; scanf("%d%d",&n,&Q); scanf("%s",ss+1); get_sa(100);get_he(); get_st(); trlen=0;memset(rt,0,sizeof(rt)); for(int i=1;i<=n;i++)//枚举排名 { rt[i]=maketree(rt[i],1,n,sa1[i]); rt[i]=merge(rt[i],rt[i-1]); } int A,B,C,D; while(Q--) { scanf("%d%d%d%d",&A,&B,&C,&D); int l=1,r=min(B-A+1,D-C+1),ans=0; while(l<=r) { int mid=(l+r)/2; getLR(Rank[C],mid); if(check(rt[L-1],rt[R],1,n,A,B-mid+1)==true) { l=mid+1; ans=mid; } else r=mid-1; } printf("%d\n",ans); } return 0; }
pain and happy in the cruel world.