葫芦的考验之定位子串
思路
后缀自动机+倍增
直接在建立的后缀树上进行查找,因为孩子和父亲一定是具有相同的后缀的,所以只需要后缀的长度足够就可以了。
代码
#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; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现