[BZOJ3230]相似子串(后缀数组)

显然可以通过后缀数组快速找到询问的两个串分别是什么,然后正反各建一个后缀数组来求两个串的LCP和LCS即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=100010,inf=1e9;
 9 char s[N];
10 ll ans,x,y;
11 int n,Q,lg[N];
12 struct P{ int x,y; };
13 
14 struct SA{
15     ll sm[N];
16     char s[N];
17     int x[N],y[N],c[N],sa[N],rk[N],h[N],mn[N][20];
18     
19     bool Cmp(int a,int b,int l){ return a+l<=n && b+l<=n && y[a]==y[b] && y[a+l]==y[b+l]; }
20     
21     void build(int m){
22         rep(i,0,m) c[i]=0;
23         rep(i,1,n) c[x[i]=s[i]-'a'+1]++;
24         rep(i,1,m) c[i]+=c[i-1];
25         for (int i=n; i; i--) sa[c[x[i]]--]=i;
26         for (int k=1,p=0; p<n; k<<=1,m=p){
27             p=0;
28             rep(i,n-k+1,n) y[++p]=i;
29             rep(i,1,n) if (sa[i]>k) y[++p]=sa[i]-k;
30             rep(i,0,m) c[i]=0;
31             rep(i,1,n) c[x[y[i]]]++;
32             rep(i,1,m) c[i]+=c[i-1];
33             for (int i=n; i; i--) sa[c[x[y[i]]]--]=y[i];
34             rep(i,1,n) y[i]=x[i]; x[sa[p=1]]=1;
35             rep(i,2,n) x[sa[i]]=Cmp(sa[i],sa[i-1],k) ? p : ++p;
36         }
37     }
38     
39     void init(){
40         rep(i,1,n) rk[sa[i]]=i;
41         int k=0;
42         rep(i,1,n){
43             for (int j=sa[rk[i]-1]; i+k<=n && j+k<=n && s[i+k]==s[j+k]; k++);
44             h[rk[i]]=k; if (k) k--;
45         }
46         rep(i,1,n) sm[i]=sm[i-1]+n-sa[i]+1-h[i],mn[i][0]=h[i];
47         rep(j,1,18) rep(i,1,n-(1<<j)+1) mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
48     }
49     
50     int que(int l,int r){
51         if (l==r) return inf;
52         l++; int t=lg[r-l+1]; return min(mn[l][t],mn[r-(1<<t)+1][t]);
53     }
54     
55     P get(ll k){
56         int L=1,R=n; int ans1,ans2;
57         if (sm[n]<k) return (P){-1,-1};
58         while (L<=R){
59             int mid=(L+R)>>1;
60             if (sm[mid]>=k) ans1=mid,ans2=n-sa[mid]+1-(sm[mid]-k),R=mid-1; else L=mid+1;
61         }
62         return (P){ans1,ans2};
63     }
64 }S1,S2;
65 
66 int main(){
67     freopen("bzoj3230.in","r",stdin);
68     freopen("bzoj3230.out","w",stdout);
69     scanf("%d%d%s",&n,&Q,s+1);
70     rep(i,2,n) lg[i]=lg[i>>1]+1;
71     rep(i,1,n) S1.s[i]=S2.s[n-i+1]=s[i];
72     S1.build(30); S2.build(30); S1.init(); S2.init();
73     rep(i,1,Q){
74         scanf("%lld%lld",&x,&y); ans=0;
75         if (S1.sm[n]<y){ puts("-1"); continue; }
76         P xx=S1.get(x),yy=S1.get(y);
77         ll k=min(S1.que(xx.x,yy.x),min(xx.y,yy.y)); ans+=k*k;
78         xx.x=S2.rk[n-S1.sa[xx.x]+2-xx.y]; yy.x=S2.rk[n-S1.sa[yy.x]+2-yy.y];
79         k=min(S2.que(min(xx.x,yy.x),max(xx.x,yy.x)),min(xx.y,yy.y)); ans+=k*k;
80         printf("%lld\n",ans);
81     }
82     return 0;
83 }

 

posted @ 2019-07-12 16:19  HocRiser  阅读(283)  评论(0编辑  收藏  举报