同时处理多个字符串的字串问题
在线写法
const int N=1e6+10;
int len[2*N],link[2*N],tr[2*N][32],con=2,last=1;
int add(int c,int last)
{
if(tr[last][c])
{
if(len[last]+1==len[tr[last][c]]) return tr[last][c];
int ne=con++,p=last,r=tr[last][c];
len[ne]=len[p]+1;
link[ne]=link[r];
link[r]=ne;
memcpy(tr[ne],tr[r],sizeof(tr[ne]));
while(p&&tr[p][c]==r)
{
tr[p][c]=ne;
p=link[p];
}
return ne;
}
int now=con++,p;
len[now]=len[last]+1;
for(p=last;p&&!tr[p][c];p=link[p])
tr[p][c]=now;
last=now;
if(!p)link[now]=1;
else
{
int r=tr[p][c];
if(len[r]==len[p]+1)link[now]=r;
else
{
int ne=con++;
len[ne]=len[p]+1;
link[ne]=link[r];
link[now]=link[r]=ne;
memcpy(tr[ne],tr[r],sizeof(tr[ne]));
while(p&&tr[p][c]==r)
{
tr[p][c]=ne;
p=link[p];
}
}
}
return last;
}
trie树离线写法求每个状态endpos大小
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int len[2*N],link[2*N],tr[2*N][32],con=2,deg[2*N],endpos[2*N],sta[N*2],par[2*N][32];
char s[N];
int h[N],to[N],nex[N],id=1;
void add(int a,int b)//trie树离线构造,求每个状态endpos大小
{
nex[id]=h[a];
h[a]=id;
to[id++]=b;
}
int insert(int c,int last)//也可用于在线构造,每次插入一个模式串之前,要把 last 设为 1
{
// cout<<c<<endl;
if(tr[last][c])
{
if(len[last]+1==len[tr[last][c]]) {return tr[last][c];}
int ne=con++,p=last,r=tr[last][c];
len[ne]=len[p]+1;
link[ne]=link[r];
link[r]=ne;
memcpy(tr[ne],tr[r],sizeof(tr[ne]));
while(p&&tr[p][c]==r)
{
tr[p][c]=ne;
p=link[p];
}
return ne;
}
int now=con++,p;
len[now]=len[last]+1;
for(p=last;p&&!tr[p][c];p=link[p])
tr[p][c]=now;
last=now;
if(!p)link[now]=1;
else
{
int r=tr[p][c];
if(len[r]==len[p]+1)link[now]=r;
else
{
int ne=con++;
len[ne]=len[p]+1;
link[ne]=link[r];
link[now]=link[r]=ne;
memcpy(tr[ne],tr[r],sizeof(tr[ne]));
while(p&&tr[p][c]==r)
{
tr[p][c]=ne;
p=link[p];
}
}
}
return last;
}
void bfs()
{
queue<int>q;
for(int i=1;i<con;++i)
if(!deg[i])q.push(i);
while(!q.empty())
{
int now=q.front();q.pop();
deg[link[now]]--;
endpos[link[now]]+=endpos[now];
if(!deg[link[now]])
{
q.push(link[now]);
}
}
}
void build()
{
queue<int>q;
q.push(0);
sta[0]=1;
while(!q.empty())
{
int now=q.front();q.pop();
for(int i=h[now];i;i=nex[i])
{
sta[to[i]]=insert(s[to[i]]-'A',sta[now]);
endpos[sta[to[i]]]++;
q.push(to[i]);
}
}
}
int main()
{
// freopen("1.txt","r",stdin);
int n,q;
cin>>n>>q;
scanf("%s",s+1);
add(0,1);
for(int i=1;i<n;++i)
{
int x;scanf("%d",&x);
add(x,i+1);
}
build();
for(int i=1;i<con;++i)
deg[link[i]]++;
bfs();
for(int i=1;i<con;++i)
par[i][0]=link[i];
for(int i=1;i<25;++i)//倍增跳link树
for(int j=1;j<con;++j)
par[j][i]=par[par[j][i-1]][i-1];
while(q--)
{
int x,l;scanf("%d%d",&x,&l);//求trie树x结点向上长度为l的字符串出现次数
x=sta[x];
for(int i=24;i>=0;--i)
{
if(len[par[x][i]]>=l)
x=par[x][i];
}
printf("%d\n",endpos[x]);
}
return 0;
}