BZOJ3230 相似子串[后缀数组+二分+st表]
给一个串,查询排名i和j的子串longest common suffix和longest common prefix
思路其实还是蛮好想的,就是码起来有点恶心。可以发现后缀拍完序之后的子串可以根据sa自前而后的顺序标子串排名,和统计不同字串那里差不多,自lcp后的是新子串,开始标记排名。实际操作时在每个后缀上标这一后缀开始第一个新子串排名,可证是单调增的,然后查询就二分查出子串开始的后缀也就是位置啦,然后用st表维护子串(所在后缀的)lcp即可。lcs的话就把串反转一下做个排序同理st表维护RMQ。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=100000+7,Log=20; 5 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 6 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 7 template<typename T>inline void read(T&x){ 8 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 9 while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();f?x-=x:1; 10 } 11 char s[2][N]; 12 int po[N],n,q,a,b,h1,r1,h2,r2,l1,l2; 13 ll q1,q2; 14 15 int cnt[2][N],h[2][N],sa[2][N],rk[2][N],y[2][N],m,p; 16 inline void suffix_sort(int l){ m=127,p=0; 17 for(register int i=1;i<=n;++i)++cnt[l][rk[l][i]=s[l][i]]; 18 for(register int i=1;i<=m;++i)cnt[l][i]+=cnt[l][i-1]; 19 for(register int i=n;i;--i)sa[l][cnt[l][rk[l][i]]--]=i; 20 for(register int k=1;k<n;k<<=1,p=0){ 21 for(register int i=n-k+1;i<=n;++i)y[l][++p]=i; 22 for(register int i=1;i<=n;++i)if(sa[l][i]>k)y[l][++p]=sa[l][i]-k; 23 for(register int i=1;i<=m;++i)cnt[l][i]=0; 24 for(register int i=1;i<=n;++i)++cnt[l][rk[l][y[l][i]]]; 25 for(register int i=1;i<=m;++i)cnt[l][i]+=cnt[l][i-1]; 26 for(register int i=n;i;--i)sa[l][cnt[l][rk[l][y[l][i]]]--]=y[l][i]; 27 swap(rk,y);rk[l][sa[l][1]]=p=1; 28 for(register int i=2;i<=n;++i)rk[l][sa[l][i]]=y[l][sa[l][i-1]]==y[l][sa[l][i]]&&y[l][sa[l][i-1]+k]==y[l][sa[l][i]+k]?p:++p; 29 if(p==n)break;m=p; 30 }p=0; 31 for(register int i=1;i<=n;h[l][rk[l][i]]=p,p?--p:1,++i)while(s[l][i+p]==s[l][sa[l][rk[l][i]-1]+p]&&++p); 32 } 33 34 ll rank[N],tot=1; 35 inline void mark(){for(register int i=1;i<=n;++i)rank[i]=tot,tot+=n-sa[0][i]+1-h[0][i];--tot;} 36 struct st_table{ 37 int lcp[N][Log]; 38 inline void build(int l){ 39 for(register int i=1;i<=n;++i)lcp[i][0]=h[l][i]; 40 for(register int k=1;k<=po[n];++k)for(register int i=1;i<=n+1-(1<<k);++i) 41 lcp[i][k]=_min(lcp[i][k-1],lcp[i+(1<<(k-1))][k-1]); 42 } 43 inline int RMQ(int l,int r){return _min(lcp[l][po[r-l+1]],lcp[r-(1<<po[r-l+1])+1][po[r-l+1]]);} 44 }pos,neg;//positive,negative 45 46 int main(){//freopen("tmp.txt","r",stdin); 47 read(n),read(q),scanf("%s",s[0]+1); 48 for(register int i=2;i<=n;++i)po[i]=(i-1)==(1<<(po[i-1]+1))?po[i-1]+1:po[i-1]; 49 for(register int i=1;i<=n;++i)s[1][i]=s[0][n-i+1]; 50 suffix_sort(0),suffix_sort(1),mark(); 51 pos.build(0),neg.build(1); 52 // for(register int i=1;i<=n;++i)cerr<<s[1][i];puts(""); 53 // for(register int i=1;i<=n;++i)cerr<<i<<" "<<rk[1][i]<<" "<<sa[1][i]<<endl; 54 for(register int i=1;i<=q;++i){ 55 read(q1),read(q2); 56 if(q1>tot||q2>tot){printf("-1\n");continue;} 57 h1=upper_bound(rank+1,rank+n+1,q1)-rank-1,h2=upper_bound(rank+1,rank+n+1,q2)-rank-1; 58 l1=sa[0][h1],l2=sa[0][h2],r1=l1+h[0][h1]+q1-rank[h1],r2=l2+h[0][h2]+q2-rank[h2]; 59 if(h1==h2)a=_min(r1,r2)-l1+1; 60 else{ 61 if(h1>h2)h1^=h2^=h1^=h2; 62 a=pos.RMQ(h1+1,h2);if((a>r1-l1+1)||(a>r2-l2+1))a=_min(r1-l1+1,r2-l2+1); 63 }//get a. 64 h1=rk[1][n-r1+1],h2=rk[1][n-r2+1];//cerr<<l1<<" "<<r1<<" "<<l2<<" "<<r2<<" "<<h1<<" "<<h2<<endl; 65 if(h1==h2)b=r1-_max(l1,l2)+1; 66 else{ 67 if(h1>h2)h1^=h2^=h1^=h2; 68 b=neg.RMQ(h1+1,h2);if((b>r1-l1+1)||(b>r2-l2+1))b=_min(r1-l1+1,r2-l2+1); 69 }//get b. 70 printf("%lld\n",1ll*a*a+1ll*b*b); 71 } 72 return 0; 73 }