【再谈后缀自动机(入门)】[SPOJLCS2]Longest Common Substring II
题目大意
给出
分析
关于后缀自动机
复习过程中再看后缀自动机,把许多初学的时候没弄懂的问题解决了。
首先要明确后缀自动机的每个节点所表示的是一个终点等价类,从根节点走到叶子节点就对应一个后缀,
后缀边所指向的节点所对应的终点等价类的终点包含当前节点的终点等价类对应的终点。
在构建的过程中
q−>len≠p−>len+1 ,说明由p 转移到q 并不是q 点所对应的最长的字符串但这却是能够增加这个终点的最长的字符串,q 所对应的长于该长度的字符串都不能增加这个终点,,所以我们新建一个节点nq ,将q 的信息复制给他(len,fail,ch) ,nq→len=p→len+1,q→fial=nq,np→fial=nq ,并且沿着后缀边走,将所有有字符c 转移且转移到q 的转移重定向至nq 。
为什么ch 也要复制?
因为这个节点对应的字符串加上转移的边所对应的字符形成的字符串的终点和这个节点的终点的没有关系,所以要保证这个节点的儿子节点所对应的字符串不变。q−>len=p−>len+1 ,则np→fial=q
这道题
每个节点保存两个值:当前字符串能够匹配这个节点对应的字符串的最大长度
然后,每次匹配完之后要沿着后缀边更新
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
#define MAXN 100000
using namespace std;
void Read(int &x){
char c;
while(c=getchar(),c!=EOF)
if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
return;
}
}
struct node{
int len,mx,nmx;
node *ch[26],*fail;
}tree[MAXN*2+10],*tcnt=tree,*root=tcnt,*l=tcnt,*r[MAXN*2+10];
char s[MAXN+10];
int ans,b[MAXN+10];
void insert(char c){
c-='a';
node *p=l,*np=++tcnt,*q,*nq;
l=np;
np->len=p->len+1;
while(p&&!p->ch[c])
p->ch[c]=np,p=p->fail;
if(!p)
np->fail=root;
else{
q=p->ch[c];
if(q->len==p->len+1)
np->fail=q;
else{
nq=++tcnt;
*nq=*q;
nq->len=p->len+1;
q->fail=nq;
np->fail=nq;
while(p&&p->ch[c]==q)
p->ch[c]=nq,p=p->fail;
}
}
}
void read(){
scanf("%s",s);
for(int i=0;s[i];i++)
insert(s[i]);
}
void solve(){
int i,len,tot;
node *p;
for(p=tree;p<=tcnt;p++){
p->mx=p->len,p->nmx=0;
b[p->len]++;
}
for(i=1;s[i-1];i++)
b[i]+=b[i-1];
for(p=tree;p<=tcnt;p++)
r[--b[p->len]]=p;
tot=tcnt-tree;
while(~scanf("%s",s)){
p=root;
len=0;
for(i=0;s[i];i++){
s[i]-='a';
if(p->ch[s[i]]){
p=p->ch[s[i]];
p->nmx=max(p->nmx,++len);
}
else{
while(p&&!p->ch[s[i]])
p=p->fail;
if(!p)
p=root,len=0;
else{
len=p->len+1;
p=p->ch[s[i]];
p->nmx=max(p->nmx,len);
}
}
}
for(i=tot;i;i--){
r[i]->fail->nmx=max(r[i]->nmx,r[i]->fail->nmx);//不用和r[i]->len进行比较,因为不会影响更新r[i]->mx
r[i]->mx=min(r[i]->mx,r[i]->nmx);
r[i]->nmx=0;
}
}
for(p=tree;p<=tcnt;p++)
ans=max(ans,p->mx);
}
int main()
{
read();
solve();
printf("%d\n",ans);
}