葫芦的考验之定位子串

葫芦的考验之定位子串

思路

后缀自动机+倍增
直接在建立的后缀树上进行查找,因为孩子和父亲一定是具有相同的后缀的,所以只需要后缀的长度足够就可以了。

代码

#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;
}
posted @   basicecho  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示