这里要在后缀自动机的节点中维护一个从到达当前位置出现的字符串总个数
这里新添加进来的节点的状态出现的次数必然为1
另外包含所能达到这个节点所能到达的状态一定是将它作为父亲的点
那么说明将它作为父亲的点添加进来一定会使它的所有父亲状态数都+1
所以直接在添加节点结束后不断向上更新
#include <cstdio>
#include <cstring>
#include <iostream> using namespace std;
#define N 200010
#define M 26 struct SamNode{
SamNode *son[] , *f;
int l , sc;
void init(){
f = NULL;
for(int i= ; i< ; i++) son[i] = NULL;
l = sc = ;
}
}*root , *last , sam[N]; int cnt , n , m , k , ret;
char s[N]; void init(){
sam[].init();
root = last = &sam[cnt=];
ret = ;
} void add(int x)
{
SamNode *p = &sam[++cnt] , *jp=last;
p->init();
p->l = jp->l+;
p->sc=;
last = p;
for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x]=p;
if(!jp) p->f = root;
else{
if(jp->l+ == jp->son[x]->l) p->f = jp->son[x];
else{
SamNode *r = &sam[++cnt] , *q = jp->son[x];
r->init();
*r = *q;
r->l = jp->l+;
q->f = p->f = r;
for( ; jp && jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
}
}
p = last;
while(p->f){
p = p->f;
p->sc++;
}
}
char str[];
int solve()
{
SamNode *cur = root;
int len = strlen(str);
for(int i= ; i<len ; i++){
int v = str[i]-'a';
if(cur->son[v]){
cur = cur->son[v];
}
else{
return ;
}
}
return cur->sc;
} int main()
{
// freopen("data_in.txt" , "r" , stdin);
int n , m , op;
while(~scanf("%d%d" , &n , &m))
{
scanf("%s" , s); init();
for(int i= ; i<n ; i++) add(s[i]-'a');
while(m--){
// cout<<m<<endl;
scanf("%d" , &op);
if(op==){
// cout<<"in"<<endl;
scanf("%s" , str);
printf("%d\n" , solve()); }
else{
scanf("%s" , str);
add(str[]-'a');
}
}
}
return ;
}