后缀自动机裸题。
借着这道裸题总结一下后缀自动机的查询问题。
1.查前缀 查询时不跳parent,遇到空节点就跳出。
2.查子串 查询时跳parent,记录最大ans.
3.查次数 LCT维护right数组
4.查不同的串的数目 在建树时维护,一个点对答案的贡献为this->max_len - this->parent->max_len
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<map>
using namespace std;
struct sam
{
sam* son[4];
sam* parent;
int max_len;
sam(int _=0):max_len(_),parent(0x0)
{
memset(son,0,sizeof(son));
}
}*root=new sam(),*last=root;
void my_insert(int x)
{
sam *p=last;
sam *np=new sam(p->max_len+1);
while(p && !p->son[x])
{
p->son[x]=np;
p=p->parent;
}
if(!p) np->parent=root;
else
{
sam *q=p->son[x];
if(q->max_len==p->max_len+1) np->parent=q;
else
{
sam *nq=new sam(p->max_len+1);
nq->parent=q->parent;
memcpy(nq->son,q->son,sizeof(nq->son));
q->parent=nq,np->parent=nq;
while(p && p->son[x]==q)
{
p->son[x]=nq;
p=p->parent;
}
}
}
last=np;
}
char s[10000000];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
if(s[i]=='E') my_insert(0);
if(s[i]=='S') my_insert(1);
if(s[i]=='W') my_insert(2);
if(s[i]=='N') my_insert(3);
}
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
sam *o=root;
int ans=0;
for(int j=1;s[j];j++)
{
int x;
if(s[j]=='E') x=0;
if(s[j]=='S') x=1;
if(s[j]=='W') x=2;
if(s[j]=='N') x=3;
if(o->son[x]) o=o->son[x],ans++;
else break;
}
printf("%d\n",ans);
}
return 0;
}