uva12338(后缀树组)
Anti-Rhyme Pairs
题意:
给出n个字符串,q个询问,每次询问为i,j两个数字,求第i个字符串和第j个字符串的最长公共前缀。
分析:
将n个字符串拼接后,第i个字符串与第j个字符串的最长公共前缀也可看作第i个字符串首字母在拼接字符串中的位置的后缀与第j个字符串首字母在拼接字符串中的位置的后缀的最长公共前缀,即height数组的含义。根据后缀树组中height数组的性质,suffix(i)和suffix(j)的最长公共前缀为height【rank【i】+1】,height【rank【i】+2】……height【rank【j】】中的最小值(代码中因为数据存储在数组中的位置不同,导致下标有所变化),用ST表维护一个区间最小值即可。
代码:
#include <map> #include <queue> #include <math.h> #include <string> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxlog=20; const int maxn=2e6; int n,q,T; char str[maxn]; int arrlen[maxn],sum[maxn]; int r[maxn],sa[maxn],Rank[maxn],height[maxn]; namespace Suffix { int wa[maxn],wb[maxn],wv[maxn],wt[maxn]; int cmp(int *r,int a,int b,int k) { return r[a]==r[b]&&r[a+k]==r[b+k]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) wt[i]=0; for(i=0; i<=n; i++) wt[x[i]=r[i]]++; for(i=1; i<m; i++) wt[i]+=wt[i-1]; for(i=n; i>=0; i--) sa[--wt[x[i]]]=i; p=1; j=1; for(; p<=n; j*=2,m=p) { for(p=0,i=n+1-j; i<=n; i++) y[p++]=i; for(i=0; i<=n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0; i<=n; i++) wv[i]=x[y[i]]; for(i=0; i<m; i++) wt[i]=0; for(i=0; i<=n; i++) wt[wv[i]]++; for(i=1; i<m; i++) wt[i]+=wt[i-1]; for(i=n; i>=0; i--) sa[--wt[wv[i]]]=y[i]; t=x; x=y; y=t; x[sa[0]]=0; for(p=1,i=1; i<=n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++; } } void getheight(int *r,int* sa,int n) { int i,j,k=0; for(i=1; i<=n; i++) Rank[sa[i]]=i; for(i=0; i<n; i++) { if(k) k--; else k=0; j=sa[Rank[i]-1]; while(r[i+k]==r[j+k]) k++; height[Rank[i]-1]=k; } } }; namespace ST { int d[maxn][maxlog]; void init(int* a,int n) { for(int i=1;i<=n;i++) d[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<j)<=n;i++){ d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } } } int query(int L,int R) { int k=0; while((1<<(k+1))<=R-L+1) k++; return min(d[L][k],d[R-(1<<k)+1][k]); } }; int main() { // freopen("in.txt","r",stdin); scanf("%d",&T); for(int kase=1;kase<=T;kase++){ int tot=0; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",str); int slen=strlen(str); arrlen[i]=slen; if(i==1) sum[i]=0; else sum[i]=sum[i-1]+arrlen[i-1]+1; for(int j=0;j<slen;j++){ r[tot++]=str[j]-'a'+1; } r[tot++]=29+i; } r[tot]=0; Suffix::da(r,sa,tot,30+n); Suffix::getheight(r,sa,tot); ST::init(height,tot); scanf("%d",&q); printf("Case %d:\n",kase); for(int i=1;i<=q;i++){ int L,R; scanf("%d %d",&L,&R); if(L==R){ printf("%d\n",arrlen[L]); continue; } L=Rank[sum[L]],R=Rank[sum[R]]; if(L>R) swap(L,R); printf("%d\n",ST::query(L,R-1)); } } return 0; }