题目描述

题解

我们可以先对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的字符串(后缀自动机+计数)的更多相关文章

  1. 模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合)

    模板—字符串—后缀自动机(后缀自动机+线段树合并求right集合) Code: #include <bits/stdc++.h> using namespace std; #define ...

  2. [TJOI2019]甲苯先生和大中锋的字符串——后缀自动机+差分

    题目链接: [TJOI2019]甲苯先生和大中锋的字符串 对原串建后缀自动机并维护$parent$树上每个点的子树大小,显然子树大小为$k$的节点所代表的子串出现过$k$次,那么我们需要将$[len[ ...

  3. Wannafly Camp 2020 Day 2D 卡拉巴什的字符串 - 后缀自动机

    动态维护任意两个后缀的lcp集合的mex,支持在串末尾追加字符. Solution 考虑在 SAM 上求两个后缀的 LCP 的过程,无非就是找它们在 fail 树上的 LCA,那么 LCP 长度就是这 ...

  4. Tjoi2019 甲苯先生和大中锋的字符串 后缀自动机_差分

    tjoi胆子好大,直接出了两道送分题...... 都 9102 年了,还有省选出模板题QAQ...... Code: #include <bits/stdc++.h> #define se ...

  5. 字符串数据结构模板/题单(后缀数组,后缀自动机,LCP,后缀平衡树,回文自动机)

    模板 后缀数组 #include<bits/stdc++.h> #define R register int using namespace std; const int N=1e6+9; ...

  6. HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)

    Reincarnation Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  7. 字符串(后缀自动机):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 ...

  8. BZOJ 3473: 字符串 [广义后缀自动机]

    3473: 字符串 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 354  Solved: 160[Submit][Status][Discuss] ...

  9. [十二省联考2019]字符串问题——后缀自动机+parent树优化建图+拓扑序DP+倍增

    题目链接: [十二省联考2019]字符串问题 首先考虑最暴力的做法就是对于每个$B$串存一下它是哪些$A$串的前缀,然后按每组支配关系连边,做一遍拓扑序DP即可. 但即使忽略判断前缀的时间,光是连边的 ...

随机推荐

  1. asp.net Json序列化

    Json作为一种数据传输格式与标准被广泛的使用在项目开发中,可以说简直离不开它.那么怎么来生成JSON格式的数据就成了我们首先需要解决的问题这里我们使用.net. 首先是获取数据 public ban ...

  2. jmeter5.0生成html报告 快速入门

    JMeter性能测试5.0时代之-多维度的图形化HTML报告 快速入门 1.确认基本配置 在jmeter.properties或者user.properties确认如下配置项: jmeter.save ...

  3. 高并发之API接口限流

    在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流 缓存 缓存的目的是提升系统访问速度和增大系统处理容量 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题解决后再 ...

  4. 关于Vue-cli 组件引入CSS样式文件

    在 Vue-cli 组件 .vue 文件中引入 css 样式表出错   由于使用Vue-cli后, 引入css 样式表 不需要 多余../../ 之类路径  现在写法也发生了改变 <style ...

  5. jQuery-mobilevalidate使用 的一些心得,小小总结

    在做M站时比较纠结的是表单验证,不像pc端,移动端的验证要求插件更小更轻量,更加灵活,说不定是冒气泡的报错提示?! 介绍一款好用的移动端的表单验证插件:jQuery-mobilevalidate: 代 ...

  6. hive安装详解

    1.安装MYSQL simon@simon-Lenovo-G400:~$ sudo apt-get install mysql-server simon@simon-Lenovo-G400:~$ su ...

  7. 如何使用apache自带的ab压力测试工具

    ab是apache自带的一个很好用的压力测试工具,当安装完apache的时候,就可以在bin下面找到ab 1 我们可以模拟100个并发用户,对一个页面发送1000个请求 ./ab -n1000 -c1 ...

  8. mysql从入门到精通

    解决MySQL Got a packet bigger than 'max_allowed_packet' bytes 问题在一次性向mysql插入的数据过大,可在my.ini中修改max_allow ...

  9. List接口方法

    package cn.zhou.com; /* * List?-------是啥? Collection 的一个子接口! * * 集合?容器? * * 区分容器,每个容器的数据结构不一样! * 集合, ...

  10. 四、docker compose

    docker compose可以方便我们快捷高效地管理容器的启动.停止以及重启等操作,和批量管理容器,它类似于linux下的shell脚本,基于yaml语法,在该文件里我们可以描述应用的架构,比如用什 ...