bzoj3756pty的字符串(后缀自动机+计数)
题目描述

题解
我们可以先对trie树建出广义SAM,然后维护一下right集合大小(注意right集合在广义SAM上的维护方式)。
然后把匹配穿往广义SAM上匹配,假设现在匹配到了x节点,那么x的所有祖先后可以被匹配上,那么一个节点的贡献即为r[x]*(l[x]-l[fa[x]])。
维护这玩意的和就好了,最下面的节点特判一下。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1600002
#define M 8000002
using namespace std;
typedef long long ll;
char c[],s[M];
int cnt,n,father,pa[N],len,tong[N],rnk[N];
ll sum[N],ans;
int l[N],ch[N][],fa[N],r[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline int ins(int last,int x){
int p=last;
if(ch[p][x]){
int q=ch[p][x];
if(l[p]+==l[q]){r[q]++;return q;}
else{
int nq=++cnt;l[nq]=l[p]+;r[nq]=;//care!!!!!!!!!!!!!!!
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
return nq;
}
}
else{
int np=++cnt;l[np]=l[p]+;r[np]=;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=;
else{
int q=ch[p][x];
if(l[p]+==l[q])fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
return np;
}
}
int main(){
n=rd();cnt=;pa[]=;
for(int i=;i<=n;++i){
father=rd();scanf("%s",c);
pa[i]=ins(pa[father],c[]-'a');
}
scanf("%s",s+);len=strlen(s+);
for(int i=;i<=cnt;++i)tong[l[i]]++;
for(int i=;i<=n;++i)tong[i]+=tong[i-];
for(int i=;i<=cnt;++i)rnk[tong[l[i]]--]=i;
for(int i=cnt;i>=;--i){int x=rnk[i];r[fa[x]]+=r[x];}
r[]=;
for(int i=;i<=cnt;++i){int x=rnk[i];sum[x]=sum[fa[x]]+1ll*(l[x]-l[fa[x]])*r[x];}
int now=,le=;
for(int i=;i<=len;++i){
if(ch[now][s[i]-'a'])le++,now=ch[now][s[i]-'a'];
else{
for(;now&&!ch[now][s[i]-'a'];now=fa[now]);
if(now)le=l[now]+,now=ch[now][s[i]-'a'];
else le=,now=;
}
if(now!=)ans+=sum[fa[now]]+1ll*(le-l[fa[now]])*r[now];
}
cout<<ans;
return ;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 1600002
#define M 8000002
using namespace std;
typedef long long ll;
char c[],s[M];
int cnt,n,father,pa[N],len,tong[N],rnk[N];
ll sum[N],ans;
int l[N],ch[N][],fa[N],r[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
inline int ins(int last,int x){
int p=last;
if(ch[p][x]){
int q=ch[p][x];
if(l[p]+==l[q]){r[q]++;return q;}
else{
int nq=++cnt;l[nq]=l[p]+;r[nq]=;//care!!!!!!!!!!!!!!!
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
return nq;
}
}
else{
int np=++cnt;l[np]=l[p]+;r[np]=;
for(;p&&!ch[p][x];p=fa[p])ch[p][x]=np;
if(!p)fa[np]=;
else{
int q=ch[p][x];
if(l[p]+==l[q])fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][x]==q;p=fa[p])ch[p][x]=nq;
}
}
return np;
}
}
int main(){
n=rd();cnt=;pa[]=;
for(int i=;i<=n;++i){
father=rd();scanf("%s",c);
pa[i]=ins(pa[father],c[]-'a');
}
scanf("%s",s+);len=strlen(s+);
for(int i=;i<=cnt;++i)tong[l[i]]++;
for(int i=;i<=n;++i)tong[i]+=tong[i-];
for(int i=;i<=cnt;++i)rnk[tong[l[i]]--]=i;
for(int i=cnt;i>=;--i){int x=rnk[i];r[fa[x]]+=r[x];}
r[]=;
for(int i=;i<=cnt;++i){int x=rnk[i];sum[x]=sum[fa[x]]+1ll*(l[x]-l[fa[x]])*r[x];}
int now=,le=;
for(int i=;i<=len;++i){
if(ch[now][s[i]-'a'])le++,now=ch[now][s[i]-'a'];
else{
for(;now&&!ch[now][s[i]-'a'];now=fa[now]);
if(now)le=l[now]+,now=ch[now][s[i]-'a'];
else le=,now=;
}
if(now!=)ans+=sum[fa[now]]+1ll*(le-l[fa[now]])*r[now];
}
cout<<ans;
return ;
}
bzoj3756pty的字符串(后缀自动机+计数)的更多相关文章
- 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)
模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...
- [TJOI2019]甲苯先生和大中锋的字符串——后缀自动机+差分
题目链接: [TJOI2019]甲苯先生和大中锋的字符串 对原串建后缀自动机并维护$parent$树上每个点的子树大小,显然子树大小为$k$的节点所代表的子串出现过$k$次,那么我们需要将$[len[ ...
- Wannafly Camp 2020 Day 2D 卡拉巴什的字符串 - 后缀自动机
动态维护任意两个后缀的lcp集合的mex,支持在串末尾追加字符. Solution 考虑在 SAM 上求两个后缀的 LCP 的过程,无非就是找它们在 fail 树上的 LCA,那么 LCP 长度就是这 ...
- Tjoi2019 甲苯先生和大中锋的字符串 后缀自动机_差分
tjoi胆子好大,直接出了两道送分题...... 都 9102 年了,还有省选出模板题QAQ...... Code: #include <bits/stdc++.h> #define se ...
- 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)
模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...
- HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)
Reincarnation Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- 字符串(后缀自动机):Codeforces Round #129 (Div. 1) E.Little Elephant and Strings
E. Little Elephant and Strings time limit per test 3 seconds memory limit per test 256 megabytes inp ...
- BZOJ 3473: 字符串 [广义后缀自动机]
3473: 字符串 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 354 Solved: 160[Submit][Status][Discuss] ...
- [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增
题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...
随机推荐
- API接口TOKEN设计
首先需要知道API是什么? API(Application Programming Interface)即应用程序接口.你可以认为 API 是一个软件组件或是一个 Web 服务与外界进行的交互的接 ...
- CMake--静态库与动态库构建
小结内容 建立一个静态库和动态库,提供 HelloFunc 函数供其他程序编程使用, HelloFunc 向终端输出Hello World 字符串. 安装头文件与共享库. 1.代码与CMakeList ...
- 【译】Six Open Source Dashboards to Organize Your Data
作者:Ben Gregory on Jun 29, 2016 译者:carsonzhu 在天文学家看来,我们相信每个组织都可以从数据的正确集中,组织和清理中受益. 我们正在建立一个公司来做到这一点 ...
- SpringBoot 中 JPA 的使用
详细连接 简书https://www.jianshu.com/p/c14640b63653 新建项目,增加依赖 在 Intellij IDEA 里面新建一个空的 SpringBoot 项目.具体步骤参 ...
- WPF Image控件的绑定
在我们平时的开发中会经常用到Image控件,通过设置Image控件的Source属性,我们可以加载图片,设置Image的source属性时可以使用相对路径也可以使用绝对路径,一般情况下建议使用绝对路径 ...
- 利用Python制作简单的小程序:IP查看器
前言 说实话,查看电脑的IP,也挺无聊的,但是够简单,所以就从这里开始吧.IP地址在操作系统里就可以直接查看.但是除了IP地址,我们也想通过IP获取地理地址和网络运营商情况.IP地址和地理地址并没有固 ...
- DAY08、文件操作
一.文件操作模式汇总: 主模式: r:读模式 w:写模式(无创建,有清空) a:追加(有创建的功能) x:写,必须自己创建文件,否则报错 从模式: t:文本操作(默认模式)r >rt,w> ...
- 如何在cmd中集成git
1.要在cmd中集成git,要解决在cmd中输入git命令时不提示git不是内部或外部命令: 即需要将git添加到path变量中,即将D:\Git\mingw64\bin和D:\Git\mingw64 ...
- LDOOP设置关联后超出新起一页LinkNewPage
关联打印的时候,top,left关联位置是相对于被关联打印项的偏移值,具体可查看本博客相关介绍博文:LODOP打印控件关联输出各内容 正常情况下,超文本超过打印项高度,或纸张高度会自动分页,如果超文本 ...
- MySQL 优化小技巧
碎片整理: mysql数据一开始是在磁盘上顺序存放的,如果数据表有频繁的update改动,那么数据就会形成很多碎片,拖慢速度和不利于索引: 优化碎片有两种方式: alter table user en ...