【bzoj3238】差异 后缀树
题目大意:给你一个字符串S,设Si是串S第i长的后缀,求:
|S|∑i=1|S|∑j=i+1|Si|+|Sj|−2×lcp(Si,Sj)
其中lcp(x,y)表示字符串x和字符串y的最长公共前缀
数据范围:|S|≤500000
最近发现后缀树和sam没学好,找一点题来做一做
一道后缀树的板题,我们用sam建出后缀树后,直接dfs遍历,通过siz更新ans即可,详情见代码
时间复杂度:O(|S|)
1 #include<bits/stdc++.h> 2 #define M 1000005 3 #define L long long 4 using namespace std; 5 6 char s[M]={0}; 7 8 struct edge{int u,v,next;}e[M]={0}; int head[M]={0},use=0; 9 void add(int x,int y,int z){use++;e[use].u=y;e[use].next=head[x];head[x]=use; e[use].v=z;} 10 L siz[M]={0},hh[M]={0},n,ans=0; 11 12 namespace sam{ 13 int ch[M][26],fa[M],l[M],use=1,last=1; 14 void exc(int c){ 15 int p=last,np=++use; l[np]=l[p]+1; last=use; hh[np]=1; 16 for(;p&&ch[p][c]==0;p=fa[p]) ch[p][c]=np; 17 if(!p) fa[np]=1; 18 else{ 19 int q=ch[p][c]; 20 if(l[p]+1==l[q]) fa[np]=q; 21 else{ 22 int nq=++use; 23 l[nq]=l[p]+1; fa[nq]=fa[q]; 24 fa[q]=fa[np]=nq; 25 memcpy(ch[nq],ch[q],sizeof(ch[q])); 26 for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq; 27 } 28 } 29 } 30 void build(){ 31 for(int i=2;i<=use;i++) add(fa[i],i,l[i]-l[fa[i]]); 32 } 33 }; 34 35 void dfs(int x,int dep){ 36 L sumsq=0; 37 for(int i=head[x];i;i=e[i].next){ 38 dfs(e[i].u,dep+e[i].v); 39 siz[x]+=siz[e[i].u]; 40 sumsq+=siz[e[i].u]*siz[e[i].u]; 41 } 42 ans-=(siz[x]*siz[x]-sumsq)*dep; 43 ans-=hh[x]*dep*siz[x]*2; 44 siz[x]+=hh[x]; 45 } 46 47 main(){ 48 scanf("%s",s+1); n=strlen(s+1); 49 for(int i=n;i;i--) sam::exc(s[i]-'a'); 50 sam::build(); 51 ans=(n-1)*(n+1)*n/2; 52 dfs(1,0); 53 cout<<ans<<endl; 54 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!