给定一个长度为 \(n\) 的字符串以及 \(q\) 组查询, 每组查询给定 \(a\) 和 \(b\), 求在全部本质不一样子串中排名第 \(a\) 和第 \(b\) 的串的最长公共前缀与最长公共后缀的平方和.php
\(n,q\le 1\times 10^5\).c++
后缀数组板子题.麻麻我终于会用后缀数组辣数组
原本想接着用SAM的...可是发现多组查询排名为 \(k\) 的本质不一样子串以我对SAM的理解好像不能作...因而就用了SA.ui
最长公共先后缀显然对正反串建两个SA就能够 \(O(n\log n)\rightarrow O(1)\) 算了. 关键在于怎么找到这两个子串.spa
把全部后缀排序后, 显然每个后缀对本质不一样子串的贡献就是和前一个后缀相同的部分以外的部分了. 那么求出全部 \(height\) 后咱们也能知道前 \(k\) 个后缀总共产生了多少本质不一样的子串. 直接二分找到子串左端点而后根据差值算出子串长度就能够了.code
由于要有两个SA, 因此简单地封到结构体里会比较好写. 然而这根本不算封装blog
#include <bits/stdc++.h> const int MAXN=1e5+10; typedef long long intEx; struct SuffixArray{ int* x; int* y; char s[MAXN]; int SA[MAXN]; int lg[MAXN]; int cnt[MAXN]; int rank[MAXN]; intEx sum[MAXN]; int height[MAXN]; int st[18][MAXN]; SuffixArray():x(new int[MAXN]),y(new int[MAXN]){} void Build(); int LCP(int,int); std::pair<int,int> Query(intEx); }; SuffixArray a,b; int n; int q; inline intEx Sqr(intEx); int main(){ scanf("%d%d",&n,&q); scanf("%s",a.s+1); for(int i=1;i<=n;i++) b.s[i]=a.s[i]; std::reverse(b.s+1,b.s+n+1); a.Build(); b.Build(); for(int i=0;i<q;i++){ intEx x,y; scanf("%lld%lld",&x,&y); auto p1=a.Query(x); auto p2=a.Query(y); if(p1.first==-1||p2.first==-1) puts("-1"); else{ intEx ans=Sqr(std::min(a.LCP(p1.first,p2.first),std::min(p1.second,p2.second))); p1.first=n-(p1.first+p1.second-1)+1; p2.first=n-(p2.first+p2.second-1)+1; ans+=Sqr(std::min(b.LCP(p1.first,p2.first),std::min(p1.second,p2.second))); printf("%lld\n",ans); } } return 0; } int SuffixArray::LCP(int x,int y){ if(x==y) return INT_MAX; else{ int l=rank[x],r=rank[y]; if(l>r) std::swap(l,r); ++l; int len=r-l+1; return std::min(st[lg[len]][l],st[lg[len]][r-(1<<lg[len])+1]); } } std::pair<int,int> SuffixArray::Query(intEx k){ int p=std::lower_bound(sum+1,sum+n+1,k)-sum; if(p==n+1) return {-1,-1}; else return {SA[p],n-(sum[p]-k)-SA[p]+1}; } void SuffixArray::Build(){ int m=127; for(int i=1;i<=n;i++) ++cnt[x[i]=s[i]]; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=n;i>=1;i--) SA[cnt[x[i]]--]=i; for(int k=1;k<n;k<<=1){ int p=0; for(int i=n-k+1;i<=n;i++) y[++p]=i; for(int i=1;i<=n;i++) if(SA[i]>k) y[++p]=SA[i]-k; memset(cnt+1,0,sizeof(int)*m); for(int i=1;i<=n;i++) ++cnt[x[i]]; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=n;i>=1;i--) SA[cnt[x[y[i]]]--]=y[i]; std::swap(x,y); x[SA[1]]=1; p=1; for(int i=2;i<=n;i++) x[SA[i]]=(y[SA[i]]==y[SA[i-1]]&&y[SA[i]+k]==y[SA[i-1]+k])?p:++p; if(p>=n) break; m=p; } for(int i=1;i<=n;i++) rank[SA[i]]=i; int k=0; for(int i=1;i<=n;i++){ if(rank[i]==1) continue; if(k!=0) --k; int j=SA[rank[i]-1]; while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) ++k; height[rank[i]]=k; st[0][rank[i]]=k; } for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(n-SA[i]+1)-height[i]; for(int i=1;(1<<i)<=n;i++){ ++lg[1<<i]; for(int j=2;j<=n;j++){ st[i][j]=st[i-1][j]; if(j+(1<<(i-1))<=n) st[i][j]=std::min(st[i][j],st[i-1][j+(1<<(i-1))]); } } for(int i=1;i<=n;i++) lg[i]+=lg[i-1]; } inline intEx Sqr(intEx x){ return x*x; }