后缀数组
之前一直以为把多个串连起来也是用同一个特殊字符,傻了。。这样会导致height数组的值可能包括特殊字符的长度。应该用不同的字符连接起来。此处因为可能有很多个串,所以合法数字就是0-25, 剩下的数字都是用来连接不同串的。
比较麻烦的就是查询的时候。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<complex>
#include<queue>
#define T 111111
using namespace std;
int s[T];
int t1[T],t2[T],cc[T],x[T],sa[T],Rank[T],height[T], belong[T], is[T];
int len;
bool cmp(int *y,int a,int b,int k)
{
int a1=y[a];
int b1=y[b];
int a2=a+k>=len ? -1:y[a+k];
int b2=b+k>=len ? -1:y[b+k];
return a1==b1 && a2==b2;
}
void make_sa()
{
int *x=t1,*y=t2;
int m=26+100000;
for(int i=0; i<m; i++) cc[i]=0;
for(int i=0; i<len; i++) ++cc[x[i]=s[i]];
for(int i=1; i<m; i++) cc[i]+=cc[i-1];
for(int i=len-1; i>=0; i--) sa[--cc[x[i]]]=i;
for(int k=1; k<=len; k<<=1)
{
int p=0;
for(int i=len-k; i<len; i++) y[p++]=i;
for(int i=0; i<len; i++)
if( sa[i]>=k ) y[p++]=sa[i]-k;
for(int i=0; i<m; i++) cc[i]=0;
for(int i=0; i<len; i++) ++cc[x[y[i]]];
for(int i=1; i<m; i++) cc[i]+=cc[i-1];
for(int i=len-1; i>=0; i--) sa[--cc[x[y[i]]]]=y[i];
swap(x,y);
m=1; x[sa[0]]=0;
for(int i=1; i<len; i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1:m++;
if( m>=len ) break;
}
}
void make_height()
{
for(int i=0; i<len; i++) Rank[sa[i]]=i;
height[0]=0;
int k=0;
for(int i=0; i<len; i++)
{
if(!Rank[i]) continue;
int j=sa[Rank[i]-1];
if(k) k--;
while(s[i+k]==s[j+k]) k++;
height[Rank[i]]=k;
}
}
int main()
{
char buff[100010];
int L[100010], ok;
int cas, cnt=27;
int n, m, x, y;
scanf("%d", &cas);
while(cas--)
{
scanf("%d", &n);
len=0;
memset(belong, 0, sizeof(belong));
memset(L, 0, sizeof(L));
for(int j=1; j<=n; j++)
{
scanf("%s", buff);
for(int i=len; i<len+strlen(buff); i++)
{
//is[i]==1表示这个串是符合规定的包含一个完整前缀的串
if(i==len)
is[i]=1;
else
is[i]=0;
s[i]=buff[i-len]-'a';
//belong[i]是指第i个字符属于第几个串,串的标号从1开始
belong[i]=j;
}
L[j]=strlen(buff);
len+=strlen(buff);
s[len++]=cnt++;
}
s[--len]='\0';
make_sa();
make_height();
scanf("%d", &m);
while(m--)
{
//flagx表示x的当前值,flag表示符合规定的包含一个完整前缀的串的长度
int flagx=0, flagy=0, flag=0, ans=0;
scanf("%d%d", &x, &y);
for(int i=0; i<len-1; i++)
{
//belong为0的值都是用来分格的数字开头的串,不用操作
if(!belong[sa[i]]) continue;
if(is[sa[i]]==1)
{
//如果找到一个符合规定的包含一个完整前缀的串
if(belong[sa[i]]==x)
{
ans=max (ans, flagy);
flagx=height[i+1];
}
else if(belong[sa[i]]==y)
{
ans=max(ans, flagx);
flagy=height[i+1];
}
else
ans=max(ans, min(flagx, flagy));
flag=height[i+1];
}
else if(belong[sa[i]]==x)
{
ans=max(ans, min(flagy, flag));
flagx=height[i+1];
}
else if(belong[sa[i]]==y)
{
ans=max(ans, min(flagx, flag));
flagy=height[i+1];
}
//因为是取min值,每次读入一个串都要把三个值更新一下
flag =min(flag, height[i+1]);
flagx=min(flagx, height[i+1]);
flagy=min(flagy, height[i+1]);
}
printf("%d\n", ans);
}
}
return 0;
}
本文深入探讨了后缀数组的构建及应用,通过具体的代码实现展示了如何处理多个字符串连接的问题,并详细解释了高度数组(height array)的计算方法。此外,还提供了一个完整的C++程序实例,用于解决特定查询问题。
1421

被折叠的 条评论
为什么被折叠?



