BZOJ3230 相似子串[后缀数组+二分+st表]

BZOJ3230 相似子串

给一个串,查询排名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
");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
",1ll*a*a+1ll*b*b);
71     }
72     return 0;
73 }
原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/10344542.html