葫芦的考验之定位子串
思路
后缀自动机+倍增
直接在建立的后缀树上进行查找,因为孩子和父亲一定是具有相同的后缀的,所以只需要后缀的长度足够就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
const int M=2.5e5+5;
struct Suffix_Auto {
char s[M];
int np=1,tot=1,n;
int ch[M<<1][26],fa[M<<1],len[M<<1],siz[M<<1],d[M];
void insert(int c,int id) {
int p=np;np=++tot;
len[np]=len[p]+1;siz[np]=1;d[id]=tot;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else {
int q=ch[p][c];
if(len[p]+1==len[q])fa[np]=q;
else {
int nq=++tot;len[nq]=len[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
int h[M<<1],e[M<<1],ne[M<<1],cnt;
void add(int from,int to) {
e[++cnt]=to; ne[cnt]=h[from]; h[from]=cnt;
}
//感觉更像一个后缀树吧,树上的后缀都是相同的
int f[M<<1][21];
void dfs(int now,int Fa) {
f[now][0]=Fa;
for(int i=1;i<=20;i++)
f[now][i]=f[f[now][i-1]][i-1];
for(int i=h[now];i;i=ne[i]) {
int to=e[i];
dfs(to,now);
siz[now]+=siz[to];
}
}
void build() {
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++)insert(s[i]-'a',i);
for(int i=2;i<=tot;i++)add(fa[i],i);
dfs(1,0);
}
int query(int l,int r) {//后缀树上查找,上面的一定和这个的后缀相同,所以只需要长度够就可以了
int Len=r-l+1;
int p=d[r];
for(int i=20;i>=0;i--)
if(len[f[p][i]]>=Len)p=f[p][i];
return siz[p];
}
void solve() {
int m;cin>>m;
while(m--) {
int l,r;
cin>>l>>r;
cout<<query(l,r)<<'\n';
}
}
}SAM;
int main() {
SAM.build();
SAM.solve();
return 0;
}

浙公网安备 33010602011771号